1:
37:
38: package ;
39:
40: import ;
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55:
56:
57:
64: public class BasicDirectoryModel extends AbstractListModel
65: implements PropertyChangeListener
66: {
67:
68: private Vector contents;
69:
70:
73: private Vector directories;
74:
75:
78: private Vector files;
79:
80:
82: private int listingMode;
83:
84:
85: private JFileChooser filechooser;
86:
87:
90: private DirectoryLoadThread loadThread;
91:
92:
96: private class DirectoryLoadThread extends Thread
97: {
98:
99:
102: private class UpdateSwingRequest
103: implements Runnable
104: {
105:
106: private List added;
107: private int addIndex;
108: private List removed;
109: private int removeIndex;
110: private boolean cancel;
111:
112: UpdateSwingRequest(List add, int ai, List rem, int ri)
113: {
114: added = add;
115: addIndex = ai;
116: removed = rem;
117: removeIndex = ri;
118: cancel = false;
119: }
120:
121: public void run()
122: {
123: if (! cancel)
124: {
125: int numRemoved = removed == null ? 0 : removed.size();
126: int numAdded = added == null ? 0 : added.size();
127: synchronized (contents)
128: {
129: if (numRemoved > 0)
130: contents.removeAll(removed);
131: if (numAdded > 0)
132: contents.addAll(added);
133:
134: files = null;
135: directories = null;
136: }
137: if (numRemoved > 0 && numAdded == 0)
138: fireIntervalRemoved(BasicDirectoryModel.this, removeIndex,
139: removeIndex + numRemoved - 1);
140: else if (numRemoved == 0 && numAdded > 0)
141: fireIntervalAdded(BasicDirectoryModel.this, addIndex,
142: addIndex + numAdded - 1);
143: else
144: fireContentsChanged();
145: }
146: }
147:
148: void cancel()
149: {
150: cancel = true;
151: }
152: }
153:
154:
157: File directory;
158:
159:
162: private UpdateSwingRequest pending;
163:
164:
170: DirectoryLoadThread(File dir)
171: {
172: super("Basic L&F directory loader");
173: directory = dir;
174: }
175:
176: public void run()
177: {
178: FileSystemView fsv = filechooser.getFileSystemView();
179: File[] files = fsv.getFiles(directory,
180: filechooser.isFileHidingEnabled());
181:
182:
183: if (isInterrupted())
184: return;
185:
186:
187: Vector accepted = new Vector();
188: for (int i = 0; i < files.length; i++)
189: {
190: if (filechooser.accept(files[i]))
191: accepted.add(files[i]);
192: }
193:
194:
195: if (isInterrupted())
196: return;
197:
198:
199: sort(accepted);
200:
201:
202:
203: Vector newFiles = new Vector();
204: Vector newDirectories = new Vector();
205: for (Iterator i = accepted.iterator(); i.hasNext();)
206: {
207: File f = (File) i.next();
208: boolean traversable = filechooser.isTraversable(f);
209: if (traversable)
210: newDirectories.add(f);
211: else if (! traversable && filechooser.isFileSelectionEnabled())
212: newFiles.add(f);
213:
214:
215: if (isInterrupted())
216: return;
217:
218: }
219:
220:
221:
222:
223: Vector newCache = new Vector(newDirectories);
224: newCache.addAll(newFiles);
225:
226: int newSize = newCache.size();
227: int oldSize = contents.size();
228: if (newSize < oldSize)
229: {
230:
231: int start = -1;
232: int end = -1;
233: boolean found = false;
234: for (int i = 0; i < newSize && !found; i++)
235: {
236: if (! newCache.get(i).equals(contents.get(i)))
237: {
238: start = i;
239: end = i + oldSize - newSize;
240: found = true;
241: }
242: }
243: if (start >= 0 && end > start
244: && contents.subList(end, oldSize)
245: .equals(newCache.subList(start, newSize)))
246: {
247:
248: if (isInterrupted())
249: return;
250:
251: Vector removed = new Vector(contents.subList(start, end));
252: UpdateSwingRequest r = new UpdateSwingRequest(null, 0,
253: removed, start);
254: invokeLater(r);
255: newCache = null;
256: }
257: }
258: else if (newSize > oldSize)
259: {
260:
261: int start = oldSize;
262: int end = newSize;
263: boolean found = false;
264: for (int i = 0; i < oldSize && ! found; i++)
265: {
266: if (! newCache.get(i).equals(contents.get(i)))
267: {
268: start = i;
269: boolean foundEnd = false;
270: for (int j = i; j < newSize && ! foundEnd; j++)
271: {
272: if (newCache.get(j).equals(contents.get(i)))
273: {
274: end = j;
275: foundEnd = true;
276: }
277: }
278: end = i + oldSize - newSize;
279: }
280: }
281: if (start >= 0 && end > start
282: && newCache.subList(end, newSize)
283: .equals(contents.subList(start, oldSize)))
284: {
285:
286: if (isInterrupted())
287: return;
288:
289: List added = newCache.subList(start, end);
290: UpdateSwingRequest r = new UpdateSwingRequest(added, start,
291: null, 0);
292: invokeLater(r);
293: newCache = null;
294: }
295: }
296:
297:
298: if (newCache != null && ! contents.equals(newCache))
299: {
300:
301: if (isInterrupted())
302: return;
303: UpdateSwingRequest r = new UpdateSwingRequest(newCache, 0,
304: contents, 0);
305: invokeLater(r);
306: }
307: }
308:
309:
315: private void invokeLater(UpdateSwingRequest update)
316: {
317: pending = update;
318: SwingUtilities.invokeLater(update);
319: }
320:
321:
325: void cancelPending()
326: {
327: if (pending != null)
328: pending.cancel();
329: }
330: }
331:
332:
333: private Comparator comparator = new Comparator()
334: {
335: public int compare(Object o1, Object o2)
336: {
337: if (lt((File) o1, (File) o2))
338: return -1;
339: else
340: return 1;
341: }
342: };
343:
344:
349: public BasicDirectoryModel(JFileChooser filechooser)
350: {
351: this.filechooser = filechooser;
352: filechooser.addPropertyChangeListener(this);
353: listingMode = filechooser.getFileSelectionMode();
354: contents = new Vector();
355: validateFileCache();
356: }
357:
358:
365: public boolean contains(Object o)
366: {
367: return contents.contains(o);
368: }
369:
370:
373: public void fireContentsChanged()
374: {
375: fireContentsChanged(this, 0, getSize() - 1);
376: }
377:
378:
384: public Vector<File> getDirectories()
385: {
386:
387:
388: synchronized (contents)
389: {
390: Vector dirs = directories;
391: if (dirs == null)
392: {
393:
394: getFiles();
395: dirs = directories;
396: }
397: return dirs;
398: }
399: }
400:
401:
408: public Object getElementAt(int index)
409: {
410: if (index > getSize() - 1)
411: return null;
412: return contents.elementAt(index);
413: }
414:
415:
421: public Vector<File> getFiles()
422: {
423: synchronized (contents)
424: {
425: Vector f = files;
426: if (f == null)
427: {
428: f = new Vector();
429: Vector d = new Vector();
430: for (Iterator i = contents.iterator(); i.hasNext();)
431: {
432: File file = (File) i.next();
433: if (filechooser.isTraversable(file))
434: d.add(file);
435: else
436: f.add(file);
437: }
438: files = f;
439: directories = d;
440: }
441: return f;
442: }
443: }
444:
445:
453: public int getSize()
454: {
455: return contents.size();
456: }
457:
458:
465: public int indexOf(Object o)
466: {
467: return contents.indexOf(o);
468: }
469:
470:
473: public void intervalAdded(ListDataEvent e)
474: {
475:
476: }
477:
478:
481: public void intervalRemoved(ListDataEvent e)
482: {
483:
484: }
485:
486:
489: public void invalidateFileCache()
490: {
491:
492: }
493:
494:
506: protected boolean lt(File a, File b)
507: {
508: boolean aTrav = filechooser.isTraversable(a);
509: boolean bTrav = filechooser.isTraversable(b);
510:
511: if (aTrav == bTrav)
512: {
513: String aname = a.getName().toLowerCase();
514: String bname = b.getName().toLowerCase();
515: return (aname.compareTo(bname) < 0) ? true : false;
516: }
517: else
518: {
519: if (aTrav)
520: return true;
521: else
522: return false;
523: }
524: }
525:
526:
532: public void propertyChange(PropertyChangeEvent e)
533: {
534: String property = e.getPropertyName();
535: if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
536: || property.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
537: || property.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY)
538: || property.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)
539: || property.equals(JFileChooser.FILE_VIEW_CHANGED_PROPERTY)
540: )
541: {
542: validateFileCache();
543: }
544: }
545:
546:
555: public boolean renameFile(File oldFile, File newFile)
556: {
557: return oldFile.renameTo( newFile );
558: }
559:
560:
565: protected void sort(Vector<? extends File> v)
566: {
567: Collections.sort(v, comparator);
568: }
569:
570:
573: public void validateFileCache()
574: {
575: File dir = filechooser.getCurrentDirectory();
576: if (dir != null)
577: {
578:
579: if (loadThread != null)
580: {
581: loadThread.interrupt();
582: loadThread.cancelPending();
583: }
584: loadThread = new DirectoryLoadThread(dir);
585: loadThread.start();
586: }
587: }
588: }