KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicDirectoryModel


1 /*
2  * @(#)BasicDirectoryModel.java 1.32 07/01/18
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import java.io.File JavaDoc;
11 import java.util.*;
12 import javax.swing.*;
13 import javax.swing.filechooser.*;
14 import javax.swing.event.*;
15 import java.beans.*;
16
17 import sun.awt.shell.ShellFolder;
18
19 /**
20  * Basic implementation of a file list.
21  *
22  * @version %i% %g%
23  * @author Jeff Dinkins
24  */

25 public class BasicDirectoryModel extends AbstractListModel implements PropertyChangeListener {
26
27     private JFileChooser filechooser = null;
28     // PENDING(jeff) pick the size more sensibly
29
private Vector fileCache = new Vector(50);
30     private LoadFilesThread loadThread = null;
31     private Vector files = null;
32     private Vector directories = null;
33     private int fetchID = 0;
34
35     public BasicDirectoryModel(JFileChooser filechooser) {
36     this.filechooser = filechooser;
37     validateFileCache();
38     }
39
40     public void propertyChange(PropertyChangeEvent e) {
41     String JavaDoc prop = e.getPropertyName();
42     if(prop == JFileChooser.DIRECTORY_CHANGED_PROPERTY ||
43        prop == JFileChooser.FILE_VIEW_CHANGED_PROPERTY ||
44        prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY ||
45        prop == JFileChooser.FILE_HIDING_CHANGED_PROPERTY ||
46        prop == JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY) {
47         validateFileCache();
48     } else if ("UI".equals(prop)) {
49         Object JavaDoc old = e.getOldValue();
50         if (old instanceof BasicFileChooserUI JavaDoc) {
51         BasicFileChooserUI JavaDoc ui = (BasicFileChooserUI JavaDoc) old;
52         BasicDirectoryModel JavaDoc model = ui.getModel();
53         if (model != null) {
54             model.invalidateFileCache();
55         }
56         }
57     } else if ("JFileChooserDialogIsClosingProperty".equals(prop)) {
58         invalidateFileCache();
59     }
60     }
61
62     /**
63      * This method is used to interrupt file loading thread.
64      */

65     public void invalidateFileCache() {
66     if (loadThread != null) {
67         loadThread.interrupt();
68         loadThread.cancelRunnables();
69         loadThread = null;
70     }
71     }
72
73     public Vector<File JavaDoc> getDirectories() {
74     synchronized(fileCache) {
75         if (directories != null) {
76         return directories;
77         }
78         Vector fls = getFiles();
79         return directories;
80     }
81     }
82
83     public Vector<File JavaDoc> getFiles() {
84     synchronized(fileCache) {
85         if (files != null) {
86         return files;
87         }
88         files = new Vector();
89         directories = new Vector();
90         directories.addElement(filechooser.getFileSystemView().createFileObject(
91         filechooser.getCurrentDirectory(), "..")
92         );
93
94         for (int i = 0; i < getSize(); i++) {
95         File JavaDoc f = (File JavaDoc)fileCache.get(i);
96         if (filechooser.isTraversable(f)) {
97             directories.add(f);
98         } else {
99             files.add(f);
100         }
101         }
102         return files;
103     }
104     }
105
106     public void validateFileCache() {
107     File JavaDoc currentDirectory = filechooser.getCurrentDirectory();
108     if (currentDirectory == null) {
109         return;
110     }
111     if (loadThread != null) {
112         loadThread.interrupt();
113             loadThread.cancelRunnables();
114     }
115     fetchID++;
116     loadThread = new LoadFilesThread(currentDirectory, fetchID);
117     loadThread.start();
118     }
119
120     /**
121      * Renames a file in the underlying file system.
122      *
123      * @param oldFile a <code>File</code> object representing
124      * the existing file
125      * @param newFile a <code>File</code> object representing
126      * the desired new file name
127      * @return <code>true</code> if rename succeeded,
128      * otherwise <code>false</code>
129      * @since 1.4
130      */

131     public boolean renameFile(File JavaDoc oldFile, File JavaDoc newFile) {
132     synchronized(fileCache) {
133         if (oldFile.renameTo(newFile)) {
134         validateFileCache();
135         return true;
136         }
137         return false;
138     }
139     }
140
141
142     public void fireContentsChanged() {
143     // System.out.println("BasicDirectoryModel: firecontentschanged");
144
fireContentsChanged(this, 0, getSize()-1);
145     }
146
147     public int getSize() {
148     return fileCache.size();
149     }
150
151     public boolean contains(Object JavaDoc o) {
152     return fileCache.contains(o);
153     }
154
155     public int indexOf(Object JavaDoc o) {
156     return fileCache.indexOf(o);
157     }
158
159     public Object JavaDoc getElementAt(int index) {
160     return fileCache.get(index);
161     }
162
163     /**
164      * Obsolete - not used.
165      */

166     public void intervalAdded(ListDataEvent e) {
167     }
168
169     /**
170      * Obsolete - not used.
171      */

172     public void intervalRemoved(ListDataEvent e) {
173     }
174
175     protected void sort(Vector<? extends File JavaDoc> v){
176     ShellFolder.sortFiles(v);
177     }
178
179     // Obsolete - not used
180
protected boolean lt(File JavaDoc a, File JavaDoc b) {
181     // First ignore case when comparing
182
int diff = a.getName().toLowerCase().compareTo(b.getName().toLowerCase());
183     if (diff != 0) {
184         return diff < 0;
185     } else {
186         // May differ in case (e.g. "mail" vs. "Mail")
187
return a.getName().compareTo(b.getName()) < 0;
188     }
189     }
190
191
192     class LoadFilesThread extends Thread JavaDoc {
193     File JavaDoc currentDirectory = null;
194     int fid;
195     Vector runnables = new Vector(10);
196     
197     public LoadFilesThread(File JavaDoc currentDirectory, int fid) {
198         super("Basic L&F File Loading Thread");
199         this.currentDirectory = currentDirectory;
200         this.fid = fid;
201     }
202     
203     private void invokeLater(Runnable JavaDoc runnable) {
204         runnables.addElement(runnable);
205         SwingUtilities.invokeLater(runnable);
206     }
207
208     public void run() {
209         FileSystemView fileSystem = filechooser.getFileSystemView();
210
211         File JavaDoc[] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled());
212
213         Vector<File JavaDoc> acceptsList = new Vector<File JavaDoc>();
214
215         if (isInterrupted()) {
216         return;
217         }
218
219         // run through the file list, add directories and selectable files to fileCache
220
for (int i = 0; i < list.length; i++) {
221         if(filechooser.accept(list[i])) {
222             acceptsList.addElement(list[i]);
223         }
224         }
225
226         if (isInterrupted()) {
227         return;
228         }
229
230         // First sort alphabetically by filename
231
sort(acceptsList);
232
233         Vector newDirectories = new Vector(50);
234         Vector newFiles = new Vector();
235         // run through list grabbing directories in chunks of ten
236
for(int i = 0; i < acceptsList.size(); i++) {
237         File JavaDoc f = (File JavaDoc) acceptsList.elementAt(i);
238         boolean isTraversable = filechooser.isTraversable(f);
239         if (isTraversable) {
240             newDirectories.addElement(f);
241         } else if (!isTraversable && filechooser.isFileSelectionEnabled()) {
242             newFiles.addElement(f);
243         }
244         if(isInterrupted()) {
245             return;
246         }
247         }
248
249         Vector newFileCache = new Vector(newDirectories);
250         newFileCache.addAll(newFiles);
251
252         int newSize = newFileCache.size();
253         int oldSize = fileCache.size();
254
255         if (newSize > oldSize) {
256         //see if interval is added
257
int start = oldSize;
258         int end = newSize;
259         for (int i = 0; i < oldSize; i++) {
260             if (!newFileCache.get(i).equals(fileCache.get(i))) {
261             start = i;
262             for (int j = i; j < newSize; j++) {
263                 if (newFileCache.get(j).equals(fileCache.get(i))) {
264                 end = j;
265                 break;
266                 }
267             }
268             break;
269             }
270         }
271         if (start >= 0 && end > start
272             && newFileCache.subList(end, newSize).equals(fileCache.subList(start, oldSize))) {
273             if(isInterrupted()) {
274                 return;
275             }
276             invokeLater(new DoChangeContents(newFileCache.subList(start, end), start, null, 0, fid));
277             newFileCache = null;
278         }
279         } else if (newSize < oldSize) {
280         //see if interval is removed
281
int start = -1;
282         int end = -1;
283         for (int i = 0; i < newSize; i++) {
284             if (!newFileCache.get(i).equals(fileCache.get(i))) {
285             start = i;
286             end = i + oldSize - newSize;
287             break;
288             }
289         }
290         if (start >= 0 && end > start
291             && fileCache.subList(end, oldSize).equals(newFileCache.subList(start, newSize))) {
292             if(isInterrupted()) {
293                 return;
294             }
295             invokeLater(new DoChangeContents(null, 0, new Vector(fileCache.subList(start, end)),
296                              start, fid));
297             newFileCache = null;
298         }
299         }
300         if (newFileCache != null && !fileCache.equals(newFileCache)) {
301             if (isInterrupted()) {
302             cancelRunnables(runnables);
303             }
304         invokeLater(new DoChangeContents(newFileCache, 0, fileCache, 0, fid));
305         }
306     }
307
308
309     public void cancelRunnables(Vector runnables) {
310         for(int i = 0; i < runnables.size(); i++) {
311         ((DoChangeContents)runnables.elementAt(i)).cancel();
312         }
313     }
314
315     public void cancelRunnables() {
316             cancelRunnables(runnables);
317     }
318    }
319
320     class DoChangeContents implements Runnable JavaDoc {
321     private List addFiles;
322     private List remFiles;
323     private boolean doFire = true;
324     private int fid;
325     private int addStart = 0;
326     private int remStart = 0;
327     private int change;
328     
329     public DoChangeContents(List addFiles, int addStart, List remFiles, int remStart, int fid) {
330         this.addFiles = addFiles;
331         this.addStart = addStart;
332         this.remFiles = remFiles;
333         this.remStart = remStart;
334         this.fid = fid;
335     }
336
337     synchronized void cancel() {
338         doFire = false;
339     }
340     
341     public synchronized void run() {
342         if (fetchID == fid && doFire) {
343         int remSize = (remFiles == null) ? 0 : remFiles.size();
344         int addSize = (addFiles == null) ? 0 : addFiles.size();
345         synchronized(fileCache) {
346             if (remSize > 0) {
347             fileCache.removeAll(remFiles);
348             }
349             if (addSize > 0) {
350             fileCache.addAll(addStart, addFiles);
351             }
352             files = null;
353             directories = null;
354         }
355         if (remSize > 0 && addSize == 0) {
356             fireIntervalRemoved(BasicDirectoryModel.this, remStart, remStart + remSize - 1);
357         } else if (addSize > 0 && remSize == 0 && fileCache.size() > addSize) {
358             fireIntervalAdded(BasicDirectoryModel.this, addStart, addStart + addSize - 1);
359         } else {
360             fireContentsChanged();
361         }
362         }
363     }
364     }
365 }
366
367
Popular Tags