1 7 8 package javax.swing.plaf.basic; 9 10 import java.io.File ; 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 25 public class BasicDirectoryModel extends AbstractListModel implements PropertyChangeListener { 26 27 private JFileChooser filechooser = null; 28 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 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 old = e.getOldValue(); 50 if (old instanceof BasicFileChooserUI ) { 51 BasicFileChooserUI ui = (BasicFileChooserUI ) old; 52 BasicDirectoryModel model = ui.getModel(); 53 if (model != null) { 54 model.invalidateFileCache(); 55 } 56 } 57 } else if ("JFileChooserDialogIsClosingProperty".equals(prop)) { 58 invalidateFileCache(); 59 } 60 } 61 62 65 public void invalidateFileCache() { 66 if (loadThread != null) { 67 loadThread.interrupt(); 68 loadThread.cancelRunnables(); 69 loadThread = null; 70 } 71 } 72 73 public Vector<File > 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 > 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 f = (File )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 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 131 public boolean renameFile(File oldFile, File 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 fireContentsChanged(this, 0, getSize()-1); 145 } 146 147 public int getSize() { 148 return fileCache.size(); 149 } 150 151 public boolean contains(Object o) { 152 return fileCache.contains(o); 153 } 154 155 public int indexOf(Object o) { 156 return fileCache.indexOf(o); 157 } 158 159 public Object getElementAt(int index) { 160 return fileCache.get(index); 161 } 162 163 166 public void intervalAdded(ListDataEvent e) { 167 } 168 169 172 public void intervalRemoved(ListDataEvent e) { 173 } 174 175 protected void sort(Vector<? extends File > v){ 176 ShellFolder.sortFiles(v); 177 } 178 179 protected boolean lt(File a, File b) { 181 int diff = a.getName().toLowerCase().compareTo(b.getName().toLowerCase()); 183 if (diff != 0) { 184 return diff < 0; 185 } else { 186 return a.getName().compareTo(b.getName()) < 0; 188 } 189 } 190 191 192 class LoadFilesThread extends Thread { 193 File currentDirectory = null; 194 int fid; 195 Vector runnables = new Vector(10); 196 197 public LoadFilesThread(File 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 runnable) { 204 runnables.addElement(runnable); 205 SwingUtilities.invokeLater(runnable); 206 } 207 208 public void run() { 209 FileSystemView fileSystem = filechooser.getFileSystemView(); 210 211 File [] list = fileSystem.getFiles(currentDirectory, filechooser.isFileHidingEnabled()); 212 213 Vector<File > acceptsList = new Vector<File >(); 214 215 if (isInterrupted()) { 216 return; 217 } 218 219 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 sort(acceptsList); 232 233 Vector newDirectories = new Vector(50); 234 Vector newFiles = new Vector(); 235 for(int i = 0; i < acceptsList.size(); i++) { 237 File f = (File ) 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 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 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 { 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 |