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