J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun in the LICENSE file that accompanied this code. |
| 10 | * |
| 11 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 14 | * version 2 for more details (a copy is included in the LICENSE file that |
| 15 | * accompanied this code). |
| 16 | * |
| 17 | * You should have received a copy of the GNU General Public License version |
| 18 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 20 | * |
| 21 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package javax.swing.filechooser; |
| 27 | |
| 28 | |
| 29 | import javax.swing.event.*; |
| 30 | import javax.swing.*; |
| 31 | |
| 32 | import java.awt.Image; |
| 33 | import java.io.File; |
| 34 | import java.io.FileFilter; |
| 35 | import java.io.FilenameFilter; |
| 36 | import java.io.FileNotFoundException; |
| 37 | import java.io.IOException; |
| 38 | import java.text.MessageFormat; |
| 39 | import java.util.ArrayList; |
| 40 | import java.util.Arrays; |
| 41 | import java.util.List; |
| 42 | import java.util.Vector; |
| 43 | import java.beans.PropertyChangeListener; |
| 44 | import java.beans.PropertyChangeEvent; |
| 45 | |
| 46 | |
| 47 | import java.lang.reflect.*; |
| 48 | |
| 49 | import sun.awt.shell.*; |
| 50 | |
| 51 | /** |
| 52 | * FileSystemView is JFileChooser's gateway to the |
| 53 | * file system. Since the JDK1.1 File API doesn't allow |
| 54 | * access to such information as root partitions, file type |
| 55 | * information, or hidden file bits, this class is designed |
| 56 | * to intuit as much OS-specific file system information as |
| 57 | * possible. |
| 58 | * |
| 59 | * <p> |
| 60 | * |
| 61 | * Java Licensees may want to provide a different implementation of |
| 62 | * FileSystemView to better handle a given operating system. |
| 63 | * |
| 64 | * @author Jeff Dinkins |
| 65 | */ |
| 66 | |
| 67 | // PENDING(jeff) - need to provide a specification for |
| 68 | // how Mac/OS2/BeOS/etc file systems can modify FileSystemView |
| 69 | // to handle their particular type of file system. |
| 70 | |
| 71 | public abstract class FileSystemView { |
| 72 | |
| 73 | static FileSystemView windowsFileSystemView = null; |
| 74 | static FileSystemView unixFileSystemView = null; |
| 75 | //static FileSystemView macFileSystemView = null; |
| 76 | static FileSystemView genericFileSystemView = null; |
| 77 | static boolean useSystemExtensionsHiding = false; |
| 78 | |
| 79 | public static FileSystemView getFileSystemView() { |
| 80 | useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); |
| 81 | UIManager.addPropertyChangeListener(new PropertyChangeListener() { |
| 82 | public void propertyChange(PropertyChangeEvent e) { |
| 83 | if (e.getPropertyName().equals("lookAndFeel")) { |
| 84 | useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); |
| 85 | } |
| 86 | } |
| 87 | }); |
| 88 | |
| 89 | if(File.separatorChar == '\\') { |
| 90 | if(windowsFileSystemView == null) { |
| 91 | windowsFileSystemView = new WindowsFileSystemView(); |
| 92 | } |
| 93 | return windowsFileSystemView; |
| 94 | } |
| 95 | |
| 96 | if(File.separatorChar == '/') { |
| 97 | if(unixFileSystemView == null) { |
| 98 | unixFileSystemView = new UnixFileSystemView(); |
| 99 | } |
| 100 | return unixFileSystemView; |
| 101 | } |
| 102 | |
| 103 | // if(File.separatorChar == ':') { |
| 104 | // if(macFileSystemView == null) { |
| 105 | // macFileSystemView = new MacFileSystemView(); |
| 106 | // } |
| 107 | // return macFileSystemView; |
| 108 | //} |
| 109 | |
| 110 | if(genericFileSystemView == null) { |
| 111 | genericFileSystemView = new GenericFileSystemView(); |
| 112 | } |
| 113 | return genericFileSystemView; |
| 114 | } |
| 115 | |
| 116 | /** |
| 117 | * Determines if the given file is a root in the navigatable tree(s). |
| 118 | * Examples: Windows 98 has one root, the Desktop folder. DOS has one root |
| 119 | * per drive letter, <code>C:\</code>, <code>D:\</code>, etc. Unix has one root, |
| 120 | * the <code>"/"</code> directory. |
| 121 | * |
| 122 | * The default implementation gets information from the <code>ShellFolder</code> class. |
| 123 | * |
| 124 | * @param f a <code>File</code> object representing a directory |
| 125 | * @return <code>true</code> if <code>f</code> is a root in the navigatable tree. |
| 126 | * @see #isFileSystemRoot |
| 127 | */ |
| 128 | public boolean isRoot(File f) { |
| 129 | if (f == null || !f.isAbsolute()) { |
| 130 | return false; |
| 131 | } |
| 132 | |
| 133 | File[] roots = getRoots(); |
| 134 | for (int i = 0; i < roots.length; i++) { |
| 135 | if (roots[i].equals(f)) { |
| 136 | return true; |
| 137 | } |
| 138 | } |
| 139 | return false; |
| 140 | } |
| 141 | |
| 142 | /** |
| 143 | * Returns true if the file (directory) can be visited. |
| 144 | * Returns false if the directory cannot be traversed. |
| 145 | * |
| 146 | * @param f the <code>File</code> |
| 147 | * @return <code>true</code> if the file/directory can be traversed, otherwise <code>false</code> |
| 148 | * @see JFileChooser#isTraversable |
| 149 | * @see FileView#isTraversable |
| 150 | * @since 1.4 |
| 151 | */ |
| 152 | public Boolean isTraversable(File f) { |
| 153 | return Boolean.valueOf(f.isDirectory()); |
| 154 | } |
| 155 | |
| 156 | /** |
| 157 | * Name of a file, directory, or folder as it would be displayed in |
| 158 | * a system file browser. Example from Windows: the "M:\" directory |
| 159 | * displays as "CD-ROM (M:)" |
| 160 | * |
| 161 | * The default implementation gets information from the ShellFolder class. |
| 162 | * |
| 163 | * @param f a <code>File</code> object |
| 164 | * @return the file name as it would be displayed by a native file chooser |
| 165 | * @see JFileChooser#getName |
| 166 | * @since 1.4 |
| 167 | */ |
| 168 | public String getSystemDisplayName(File f) { |
| 169 | String name = null; |
| 170 | if (f != null) { |
| 171 | name = f.getName(); |
| 172 | if (!name.equals("..") && !name.equals(".") && |
| 173 | (useSystemExtensionsHiding || |
| 174 | !isFileSystem(f) || |
| 175 | isFileSystemRoot(f)) && |
| 176 | ((f instanceof ShellFolder) || |
| 177 | f.exists())) { |
| 178 | |
| 179 | name = getShellFolder(f).getDisplayName(); |
| 180 | if (name == null || name.length() == 0) { |
| 181 | name = f.getPath(); // e.g. "/" |
| 182 | } |
| 183 | } |
| 184 | } |
| 185 | return name; |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * Type description for a file, directory, or folder as it would be displayed in |
| 190 | * a system file browser. Example from Windows: the "Desktop" folder |
| 191 | * is desribed as "Desktop". |
| 192 | * |
| 193 | * Override for platforms with native ShellFolder implementations. |
| 194 | * |
| 195 | * @param f a <code>File</code> object |
| 196 | * @return the file type description as it would be displayed by a native file chooser |
| 197 | * or null if no native information is available. |
| 198 | * @see JFileChooser#getTypeDescription |
| 199 | * @since 1.4 |
| 200 | */ |
| 201 | public String getSystemTypeDescription(File f) { |
| 202 | return null; |
| 203 | } |
| 204 | |
| 205 | /** |
| 206 | * Icon for a file, directory, or folder as it would be displayed in |
| 207 | * a system file browser. Example from Windows: the "M:\" directory |
| 208 | * displays a CD-ROM icon. |
| 209 | * |
| 210 | * The default implementation gets information from the ShellFolder class. |
| 211 | * |
| 212 | * @param f a <code>File</code> object |
| 213 | * @return an icon as it would be displayed by a native file chooser |
| 214 | * @see JFileChooser#getIcon |
| 215 | * @since 1.4 |
| 216 | */ |
| 217 | public Icon getSystemIcon(File f) { |
| 218 | if (f != null) { |
| 219 | ShellFolder sf = getShellFolder(f); |
| 220 | Image img = sf.getIcon(false); |
| 221 | if (img != null) { |
| 222 | return new ImageIcon(img, sf.getFolderType()); |
| 223 | } else { |
| 224 | return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon"); |
| 225 | } |
| 226 | } else { |
| 227 | return null; |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | /** |
| 232 | * On Windows, a file can appear in multiple folders, other than its |
| 233 | * parent directory in the filesystem. Folder could for example be the |
| 234 | * "Desktop" folder which is not the same as file.getParentFile(). |
| 235 | * |
| 236 | * @param folder a <code>File</code> object repesenting a directory or special folder |
| 237 | * @param file a <code>File</code> object |
| 238 | * @return <code>true</code> if <code>folder</code> is a directory or special folder and contains <code>file</code>. |
| 239 | * @since 1.4 |
| 240 | */ |
| 241 | public boolean isParent(File folder, File file) { |
| 242 | if (folder == null || file == null) { |
| 243 | return false; |
| 244 | } else if (folder instanceof ShellFolder) { |
| 245 | File parent = file.getParentFile(); |
| 246 | if (parent != null && parent.equals(folder)) { |
| 247 | return true; |
| 248 | } |
| 249 | File[] children = getFiles(folder, false); |
| 250 | for (int i = 0; i < children.length; i++) { |
| 251 | if (file.equals(children[i])) { |
| 252 | return true; |
| 253 | } |
| 254 | } |
| 255 | return false; |
| 256 | } else { |
| 257 | return folder.equals(file.getParentFile()); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | /** |
| 262 | * |
| 263 | * @param parent a <code>File</code> object repesenting a directory or special folder |
| 264 | * @param fileName a name of a file or folder which exists in <code>parent</code> |
| 265 | * @return a File object. This is normally constructed with <code>new |
| 266 | * File(parent, fileName)</code> except when parent and child are both |
| 267 | * special folders, in which case the <code>File</code> is a wrapper containing |
| 268 | * a <code>ShellFolder</code> object. |
| 269 | * @since 1.4 |
| 270 | */ |
| 271 | public File getChild(File parent, String fileName) { |
| 272 | if (parent instanceof ShellFolder) { |
| 273 | File[] children = getFiles(parent, false); |
| 274 | for (int i = 0; i < children.length; i++) { |
| 275 | if (children[i].getName().equals(fileName)) { |
| 276 | return children[i]; |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | return createFileObject(parent, fileName); |
| 281 | } |
| 282 | |
| 283 | |
| 284 | /** |
| 285 | * Checks if <code>f</code> represents a real directory or file as opposed to a |
| 286 | * special folder such as <code>"Desktop"</code>. Used by UI classes to decide if |
| 287 | * a folder is selectable when doing directory choosing. |
| 288 | * |
| 289 | * @param f a <code>File</code> object |
| 290 | * @return <code>true</code> if <code>f</code> is a real file or directory. |
| 291 | * @since 1.4 |
| 292 | */ |
| 293 | public boolean isFileSystem(File f) { |
| 294 | if (f instanceof ShellFolder) { |
| 295 | ShellFolder sf = (ShellFolder)f; |
| 296 | // Shortcuts to directories are treated as not being file system objects, |
| 297 | // so that they are never returned by JFileChooser. |
| 298 | return sf.isFileSystem() && !(sf.isLink() && sf.isDirectory()); |
| 299 | } else { |
| 300 | return true; |
| 301 | } |
| 302 | } |
| 303 | |
| 304 | /** |
| 305 | * Creates a new folder with a default folder name. |
| 306 | */ |
| 307 | public abstract File createNewFolder(File containingDir) throws IOException; |
| 308 | |
| 309 | /** |
| 310 | * Returns whether a file is hidden or not. |
| 311 | */ |
| 312 | public boolean isHiddenFile(File f) { |
| 313 | return f.isHidden(); |
| 314 | } |
| 315 | |
| 316 | |
| 317 | /** |
| 318 | * Is dir the root of a tree in the file system, such as a drive |
| 319 | * or partition. Example: Returns true for "C:\" on Windows 98. |
| 320 | * |
| 321 | * @param dir a <code>File</code> object representing a directory |
| 322 | * @return <code>true</code> if <code>f</code> is a root of a filesystem |
| 323 | * @see #isRoot |
| 324 | * @since 1.4 |
| 325 | */ |
| 326 | public boolean isFileSystemRoot(File dir) { |
| 327 | return ShellFolder.isFileSystemRoot(dir); |
| 328 | } |
| 329 | |
| 330 | /** |
| 331 | * Used by UI classes to decide whether to display a special icon |
| 332 | * for drives or partitions, e.g. a "hard disk" icon. |
| 333 | * |
| 334 | * The default implementation has no way of knowing, so always returns false. |
| 335 | * |
| 336 | * @param dir a directory |
| 337 | * @return <code>false</code> always |
| 338 | * @since 1.4 |
| 339 | */ |
| 340 | public boolean isDrive(File dir) { |
| 341 | return false; |
| 342 | } |
| 343 | |
| 344 | /** |
| 345 | * Used by UI classes to decide whether to display a special icon |
| 346 | * for a floppy disk. Implies isDrive(dir). |
| 347 | * |
| 348 | * The default implementation has no way of knowing, so always returns false. |
| 349 | * |
| 350 | * @param dir a directory |
| 351 | * @return <code>false</code> always |
| 352 | * @since 1.4 |
| 353 | */ |
| 354 | public boolean isFloppyDrive(File dir) { |
| 355 | return false; |
| 356 | } |
| 357 | |
| 358 | /** |
| 359 | * Used by UI classes to decide whether to display a special icon |
| 360 | * for a computer node, e.g. "My Computer" or a network server. |
| 361 | * |
| 362 | * The default implementation has no way of knowing, so always returns false. |
| 363 | * |
| 364 | * @param dir a directory |
| 365 | * @return <code>false</code> always |
| 366 | * @since 1.4 |
| 367 | */ |
| 368 | public boolean isComputerNode(File dir) { |
| 369 | return ShellFolder.isComputerNode(dir); |
| 370 | } |
| 371 | |
| 372 | |
| 373 | /** |
| 374 | * Returns all root partitions on this system. For example, on |
| 375 | * Windows, this would be the "Desktop" folder, while on DOS this |
| 376 | * would be the A: through Z: drives. |
| 377 | */ |
| 378 | public File[] getRoots() { |
| 379 | // Don't cache this array, because filesystem might change |
| 380 | File[] roots = (File[])ShellFolder.get("roots"); |
| 381 | |
| 382 | for (int i = 0; i < roots.length; i++) { |
| 383 | if (isFileSystemRoot(roots[i])) { |
| 384 | roots[i] = createFileSystemRoot(roots[i]); |
| 385 | } |
| 386 | } |
| 387 | return roots; |
| 388 | } |
| 389 | |
| 390 | |
| 391 | // Providing default implementations for the remaining methods |
| 392 | // because most OS file systems will likely be able to use this |
| 393 | // code. If a given OS can't, override these methods in its |
| 394 | // implementation. |
| 395 | |
| 396 | public File getHomeDirectory() { |
| 397 | return createFileObject(System.getProperty("user.home")); |
| 398 | } |
| 399 | |
| 400 | /** |
| 401 | * Return the user's default starting directory for the file chooser. |
| 402 | * |
| 403 | * @return a <code>File</code> object representing the default |
| 404 | * starting folder |
| 405 | * @since 1.4 |
| 406 | */ |
| 407 | public File getDefaultDirectory() { |
| 408 | File f = (File)ShellFolder.get("fileChooserDefaultFolder"); |
| 409 | if (isFileSystemRoot(f)) { |
| 410 | f = createFileSystemRoot(f); |
| 411 | } |
| 412 | return f; |
| 413 | } |
| 414 | |
| 415 | /** |
| 416 | * Returns a File object constructed in dir from the given filename. |
| 417 | */ |
| 418 | public File createFileObject(File dir, String filename) { |
| 419 | if(dir == null) { |
| 420 | return new File(filename); |
| 421 | } else { |
| 422 | return new File(dir, filename); |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * Returns a File object constructed from the given path string. |
| 428 | */ |
| 429 | public File createFileObject(String path) { |
| 430 | File f = new File(path); |
| 431 | if (isFileSystemRoot(f)) { |
| 432 | f = createFileSystemRoot(f); |
| 433 | } |
| 434 | return f; |
| 435 | } |
| 436 | |
| 437 | |
| 438 | /** |
| 439 | * Gets the list of shown (i.e. not hidden) files. |
| 440 | */ |
| 441 | public File[] getFiles(File dir, boolean useFileHiding) { |
| 442 | Vector files = new Vector(); |
| 443 | |
| 444 | |
| 445 | // add all files in dir |
| 446 | File[] names; |
| 447 | if (!(dir instanceof ShellFolder)) { |
| 448 | dir = getShellFolder(dir); |
| 449 | } |
| 450 | |
| 451 | names = ((ShellFolder)dir).listFiles(!useFileHiding); |
| 452 | File f; |
| 453 | |
| 454 | int nameCount = (names == null) ? 0 : names.length; |
| 455 | for (int i = 0; i < nameCount; i++) { |
| 456 | if (Thread.currentThread().isInterrupted()) { |
| 457 | break; |
| 458 | } |
| 459 | f = names[i]; |
| 460 | if (!(f instanceof ShellFolder)) { |
| 461 | if (isFileSystemRoot(f)) { |
| 462 | f = createFileSystemRoot(f); |
| 463 | } |
| 464 | try { |
| 465 | f = ShellFolder.getShellFolder(f); |
| 466 | } catch (FileNotFoundException e) { |
| 467 | // Not a valid file (wouldn't show in native file chooser) |
| 468 | // Example: C:\pagefile.sys |
| 469 | continue; |
| 470 | } catch (InternalError e) { |
| 471 | // Not a valid file (wouldn't show in native file chooser) |
| 472 | // Example C:\Winnt\Profiles\joe\history\History.IE5 |
| 473 | continue; |
| 474 | } |
| 475 | } |
| 476 | if (!useFileHiding || !isHiddenFile(f)) { |
| 477 | files.addElement(f); |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | return (File[])files.toArray(new File[files.size()]); |
| 482 | } |
| 483 | |
| 484 | |
| 485 | |
| 486 | /** |
| 487 | * Returns the parent directory of <code>dir</code>. |
| 488 | * @param dir the <code>File</code> being queried |
| 489 | * @return the parent directory of <code>dir</code>, or |
| 490 | * <code>null</code> if <code>dir</code> is <code>null</code> |
| 491 | */ |
| 492 | public File getParentDirectory(File dir) { |
| 493 | if (dir != null && dir.exists()) { |
| 494 | ShellFolder sf = getShellFolder(dir); |
| 495 | File psf = sf.getParentFile(); |
| 496 | if (psf != null) { |
| 497 | if (isFileSystem(psf)) { |
| 498 | File f = psf; |
| 499 | if (f != null && !f.exists()) { |
| 500 | // This could be a node under "Network Neighborhood". |
| 501 | File ppsf = psf.getParentFile(); |
| 502 | if (ppsf == null || !isFileSystem(ppsf)) { |
| 503 | // We're mostly after the exists() override for windows below. |
| 504 | f = createFileSystemRoot(f); |
| 505 | } |
| 506 | } |
| 507 | return f; |
| 508 | } else { |
| 509 | return psf; |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | return null; |
| 514 | } |
| 515 | |
| 516 | ShellFolder getShellFolder(File f) { |
| 517 | if (!(f instanceof ShellFolder) |
| 518 | && !(f instanceof FileSystemRoot) |
| 519 | && isFileSystemRoot(f)) { |
| 520 | |
| 521 | f = createFileSystemRoot(f); |
| 522 | } |
| 523 | try { |
| 524 | return ShellFolder.getShellFolder(f); |
| 525 | } catch (FileNotFoundException e) { |
| 526 | System.err.println("FileSystemView.getShellFolder: f="+f); |
| 527 | e.printStackTrace(); |
| 528 | return null; |
| 529 | } catch (InternalError e) { |
| 530 | System.err.println("FileSystemView.getShellFolder: f="+f); |
| 531 | e.printStackTrace(); |
| 532 | return null; |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /** |
| 537 | * Creates a new <code>File</code> object for <code>f</code> with correct |
| 538 | * behavior for a file system root directory. |
| 539 | * |
| 540 | * @param f a <code>File</code> object representing a file system root |
| 541 | * directory, for example "/" on Unix or "C:\" on Windows. |
| 542 | * @return a new <code>File</code> object |
| 543 | * @since 1.4 |
| 544 | */ |
| 545 | protected File createFileSystemRoot(File f) { |
| 546 | return new FileSystemRoot(f); |
| 547 | } |
| 548 | |
| 549 | |
| 550 | |
| 551 | |
| 552 | static class FileSystemRoot extends File { |
| 553 | public FileSystemRoot(File f) { |
| 554 | super(f,""); |
| 555 | } |
| 556 | |
| 557 | public FileSystemRoot(String s) { |
| 558 | super(s); |
| 559 | } |
| 560 | |
| 561 | public boolean isDirectory() { |
| 562 | return true; |
| 563 | } |
| 564 | |
| 565 | public String getName() { |
| 566 | return getPath(); |
| 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | /** |
| 572 | * FileSystemView that handles some specific unix-isms. |
| 573 | */ |
| 574 | class UnixFileSystemView extends FileSystemView { |
| 575 | |
| 576 | private static final String newFolderString = |
| 577 | UIManager.getString("FileChooser.other.newFolder"); |
| 578 | private static final String newFolderNextString = |
| 579 | UIManager.getString("FileChooser.other.newFolder.subsequent"); |
| 580 | |
| 581 | /** |
| 582 | * Creates a new folder with a default folder name. |
| 583 | */ |
| 584 | public File createNewFolder(File containingDir) throws IOException { |
| 585 | if(containingDir == null) { |
| 586 | throw new IOException("Containing directory is null:"); |
| 587 | } |
| 588 | File newFolder = null; |
| 589 | // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE. |
| 590 | newFolder = createFileObject(containingDir, newFolderString); |
| 591 | int i = 1; |
| 592 | while (newFolder.exists() && (i < 100)) { |
| 593 | newFolder = createFileObject(containingDir, MessageFormat.format( |
| 594 | newFolderNextString, new Object[] { new Integer(i) })); |
| 595 | i++; |
| 596 | } |
| 597 | |
| 598 | if(newFolder.exists()) { |
| 599 | throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); |
| 600 | } else { |
| 601 | newFolder.mkdirs(); |
| 602 | } |
| 603 | |
| 604 | return newFolder; |
| 605 | } |
| 606 | |
| 607 | public boolean isFileSystemRoot(File dir) { |
| 608 | return (dir != null && dir.getAbsolutePath().equals("/")); |
| 609 | } |
| 610 | |
| 611 | public boolean isDrive(File dir) { |
| 612 | if (isFloppyDrive(dir)) { |
| 613 | return true; |
| 614 | } else { |
| 615 | return false; |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | public boolean isFloppyDrive(File dir) { |
| 620 | // Could be looking at the path for Solaris, but wouldn't be reliable. |
| 621 | // For example: |
| 622 | // return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy")); |
| 623 | return false; |
| 624 | } |
| 625 | |
| 626 | public boolean isComputerNode(File dir) { |
| 627 | if (dir != null) { |
| 628 | String parent = dir.getParent(); |
| 629 | if (parent != null && parent.equals("/net")) { |
| 630 | return true; |
| 631 | } |
| 632 | } |
| 633 | return false; |
| 634 | } |
| 635 | } |
| 636 | |
| 637 | |
| 638 | /** |
| 639 | * FileSystemView that handles some specific windows concepts. |
| 640 | */ |
| 641 | class WindowsFileSystemView extends FileSystemView { |
| 642 | |
| 643 | private static final String newFolderString = |
| 644 | UIManager.getString("FileChooser.win32.newFolder"); |
| 645 | private static final String newFolderNextString = |
| 646 | UIManager.getString("FileChooser.win32.newFolder.subsequent"); |
| 647 | |
| 648 | public Boolean isTraversable(File f) { |
| 649 | return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory()); |
| 650 | } |
| 651 | |
| 652 | public File getChild(File parent, String fileName) { |
| 653 | if (fileName.startsWith("\\") |
| 654 | && !(fileName.startsWith("\\\\")) |
| 655 | && isFileSystem(parent)) { |
| 656 | |
| 657 | //Path is relative to the root of parent's drive |
| 658 | String path = parent.getAbsolutePath(); |
| 659 | if (path.length() >= 2 |
| 660 | && path.charAt(1) == ':' |
| 661 | && Character.isLetter(path.charAt(0))) { |
| 662 | |
| 663 | return createFileObject(path.substring(0, 2) + fileName); |
| 664 | } |
| 665 | } |
| 666 | return super.getChild(parent, fileName); |
| 667 | } |
| 668 | |
| 669 | /** |
| 670 | * Type description for a file, directory, or folder as it would be displayed in |
| 671 | * a system file browser. Example from Windows: the "Desktop" folder |
| 672 | * is desribed as "Desktop". |
| 673 | * |
| 674 | * The Windows implementation gets information from the ShellFolder class. |
| 675 | */ |
| 676 | public String getSystemTypeDescription(File f) { |
| 677 | if (f != null) { |
| 678 | return getShellFolder(f).getFolderType(); |
| 679 | } else { |
| 680 | return null; |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | /** |
| 685 | * @return the Desktop folder. |
| 686 | */ |
| 687 | public File getHomeDirectory() { |
| 688 | return getRoots()[0]; |
| 689 | } |
| 690 | |
| 691 | /** |
| 692 | * Creates a new folder with a default folder name. |
| 693 | */ |
| 694 | public File createNewFolder(File containingDir) throws IOException { |
| 695 | if(containingDir == null) { |
| 696 | throw new IOException("Containing directory is null:"); |
| 697 | } |
| 698 | File newFolder = null; |
| 699 | // Using NT's default folder name |
| 700 | newFolder = createFileObject(containingDir, newFolderString); |
| 701 | int i = 2; |
| 702 | while (newFolder.exists() && (i < 100)) { |
| 703 | newFolder = createFileObject(containingDir, MessageFormat.format( |
| 704 | newFolderNextString, new Object[] { new Integer(i) })); |
| 705 | i++; |
| 706 | } |
| 707 | |
| 708 | if(newFolder.exists()) { |
| 709 | throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); |
| 710 | } else { |
| 711 | newFolder.mkdirs(); |
| 712 | } |
| 713 | |
| 714 | return newFolder; |
| 715 | } |
| 716 | |
| 717 | public boolean isDrive(File dir) { |
| 718 | return isFileSystemRoot(dir); |
| 719 | } |
| 720 | |
| 721 | public boolean isFloppyDrive(File dir) { |
| 722 | String path = dir.getAbsolutePath(); |
| 723 | return (path != null && (path.equals("A:\\") || path.equals("B:\\"))); |
| 724 | } |
| 725 | |
| 726 | /** |
| 727 | * Returns a File object constructed from the given path string. |
| 728 | */ |
| 729 | public File createFileObject(String path) { |
| 730 | // Check for missing backslash after drive letter such as "C:" or "C:filename" |
| 731 | if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) { |
| 732 | if (path.length() == 2) { |
| 733 | path += "\\"; |
| 734 | } else if (path.charAt(2) != '\\') { |
| 735 | path = path.substring(0, 2) + "\\" + path.substring(2); |
| 736 | } |
| 737 | } |
| 738 | return super.createFileObject(path); |
| 739 | } |
| 740 | |
| 741 | protected File createFileSystemRoot(File f) { |
| 742 | // Problem: Removable drives on Windows return false on f.exists() |
| 743 | // Workaround: Override exists() to always return true. |
| 744 | return new FileSystemRoot(f) { |
| 745 | public boolean exists() { |
| 746 | return true; |
| 747 | } |
| 748 | }; |
| 749 | } |
| 750 | |
| 751 | } |
| 752 | |
| 753 | /** |
| 754 | * Fallthrough FileSystemView in case we can't determine the OS. |
| 755 | */ |
| 756 | class GenericFileSystemView extends FileSystemView { |
| 757 | |
| 758 | private static final String newFolderString = |
| 759 | UIManager.getString("FileChooser.other.newFolder"); |
| 760 | |
| 761 | /** |
| 762 | * Creates a new folder with a default folder name. |
| 763 | */ |
| 764 | public File createNewFolder(File containingDir) throws IOException { |
| 765 | if(containingDir == null) { |
| 766 | throw new IOException("Containing directory is null:"); |
| 767 | } |
| 768 | File newFolder = null; |
| 769 | // Using NT's default folder name |
| 770 | newFolder = createFileObject(containingDir, newFolderString); |
| 771 | |
| 772 | if(newFolder.exists()) { |
| 773 | throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); |
| 774 | } else { |
| 775 | newFolder.mkdirs(); |
| 776 | } |
| 777 | |
| 778 | return newFolder; |
| 779 | } |
| 780 | |
| 781 | } |