1 /* 2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.filechooser; 27 28 29 import javax.swing.*; 30 31 import java.awt.Image; 32 import java.io.File; 33 import java.io.FileNotFoundException; 34 import java.io.IOException; 35 import java.text.MessageFormat; 36 import java.util.List; 37 import java.util.ArrayList; 38 import java.lang.ref.WeakReference; 39 import java.beans.PropertyChangeListener; 40 import java.beans.PropertyChangeEvent; 41 import java.security.AccessController; 42 import java.security.PrivilegedAction; 43 44 import sun.awt.shell.*; 45 46 /** 47 * FileSystemView is JFileChooser's gateway to the 48 * file system. Since the JDK1.1 File API doesn't allow 49 * access to such information as root partitions, file type 50 * information, or hidden file bits, this class is designed 51 * to intuit as much OS-specific file system information as 52 * possible. 53 * 54 * <p> 55 * 56 * Java Licensees may want to provide a different implementation of 57 * FileSystemView to better handle a given operating system. 58 * 59 * @author Jeff Dinkins 60 */ 61 62 // PENDING(jeff) - need to provide a specification for 63 // how Mac/OS2/BeOS/etc file systems can modify FileSystemView 64 // to handle their particular type of file system. 65 66 public abstract class FileSystemView { 67 68 static FileSystemView windowsFileSystemView = null; 69 static FileSystemView unixFileSystemView = null; 70 //static FileSystemView macFileSystemView = null; 71 static FileSystemView genericFileSystemView = null; 72 73 private boolean useSystemExtensionHiding = 74 UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); 75 76 /** 77 * Returns the file system view. 78 * @return the file system view 79 */ 80 public static FileSystemView getFileSystemView() { 81 if(File.separatorChar == '\\') { 82 if(windowsFileSystemView == null) { 83 windowsFileSystemView = new WindowsFileSystemView(); 84 } 85 return windowsFileSystemView; 86 } 87 88 if(File.separatorChar == '/') { 89 if(unixFileSystemView == null) { 90 unixFileSystemView = new UnixFileSystemView(); 91 } 92 return unixFileSystemView; 93 } 94 95 // if(File.separatorChar == ':') { 96 // if(macFileSystemView == null) { 97 // macFileSystemView = new MacFileSystemView(); 98 // } 99 // return macFileSystemView; 100 //} 101 102 if(genericFileSystemView == null) { 103 genericFileSystemView = new GenericFileSystemView(); 104 } 105 return genericFileSystemView; 106 } 107 108 /** 109 * Constructs a FileSystemView. 110 */ 111 public FileSystemView() { 112 final WeakReference<FileSystemView> weakReference = new WeakReference<FileSystemView>(this); 113 114 UIManager.addPropertyChangeListener(new PropertyChangeListener() { 115 public void propertyChange(PropertyChangeEvent evt) { 116 FileSystemView fileSystemView = weakReference.get(); 117 118 if (fileSystemView == null) { 119 // FileSystemView was destroyed 120 UIManager.removePropertyChangeListener(this); 121 } else { 122 if (evt.getPropertyName().equals("lookAndFeel")) { 123 fileSystemView.useSystemExtensionHiding = 124 UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); 125 } 126 } 127 } 128 }); 129 } 130 131 /** 132 * Determines if the given file is a root in the navigable tree(s). 133 * Examples: Windows 98 has one root, the Desktop folder. DOS has one root 134 * per drive letter, <code>C:\</code>, <code>D:\</code>, etc. Unix has one root, 135 * the <code>"/"</code> directory. 136 * 137 * The default implementation gets information from the <code>ShellFolder</code> class. 138 * 139 * @param f a <code>File</code> object representing a directory 140 * @return <code>true</code> if <code>f</code> is a root in the navigable tree. 141 * @see #isFileSystemRoot 142 */ 143 public boolean isRoot(File f) { 144 if (f == null || !f.isAbsolute()) { 145 return false; 146 } 147 148 File[] roots = getRoots(); 149 for (File root : roots) { 150 if (root.equals(f)) { 151 return true; 152 } 153 } 154 return false; 155 } 156 157 /** 158 * Returns true if the file (directory) can be visited. 159 * Returns false if the directory cannot be traversed. 160 * 161 * @param f the <code>File</code> 162 * @return <code>true</code> if the file/directory can be traversed, otherwise <code>false</code> 163 * @see JFileChooser#isTraversable 164 * @see FileView#isTraversable 165 * @since 1.4 166 */ 167 public Boolean isTraversable(File f) { 168 return Boolean.valueOf(f.isDirectory()); 169 } 170 171 /** 172 * Name of a file, directory, or folder as it would be displayed in 173 * a system file browser. Example from Windows: the "M:\" directory 174 * displays as "CD-ROM (M:)" 175 * 176 * The default implementation gets information from the ShellFolder class. 177 * 178 * @param f a <code>File</code> object 179 * @return the file name as it would be displayed by a native file chooser 180 * @see JFileChooser#getName 181 * @since 1.4 182 */ 183 public String getSystemDisplayName(File f) { 184 if (f == null) { 185 return null; 186 } 187 188 String name = f.getName(); 189 190 if (!name.equals("..") && !name.equals(".") && 191 (useSystemExtensionHiding || !isFileSystem(f) || isFileSystemRoot(f)) && 192 (f instanceof ShellFolder || f.exists())) { 193 194 try { 195 name = getShellFolder(f).getDisplayName(); 196 } catch (FileNotFoundException e) { 197 return null; 198 } 199 200 if (name == null || name.length() == 0) { 201 name = f.getPath(); // e.g. "/" 202 } 203 } 204 205 return name; 206 } 207 208 /** 209 * Type description for a file, directory, or folder as it would be displayed in 210 * a system file browser. Example from Windows: the "Desktop" folder 211 * is described as "Desktop". 212 * 213 * Override for platforms with native ShellFolder implementations. 214 * 215 * @param f a <code>File</code> object 216 * @return the file type description as it would be displayed by a native file chooser 217 * or null if no native information is available. 218 * @see JFileChooser#getTypeDescription 219 * @since 1.4 220 */ 221 public String getSystemTypeDescription(File f) { 222 return null; 223 } 224 225 /** 226 * Icon for a file, directory, or folder as it would be displayed in 227 * a system file browser. Example from Windows: the "M:\" directory 228 * displays a CD-ROM icon. 229 * 230 * The default implementation gets information from the ShellFolder class. 231 * 232 * @param f a <code>File</code> object 233 * @return an icon as it would be displayed by a native file chooser 234 * @see JFileChooser#getIcon 235 * @since 1.4 236 */ 237 public Icon getSystemIcon(File f) { 238 if (f == null) { 239 return null; 240 } 241 242 ShellFolder sf; 243 244 try { 245 sf = getShellFolder(f); 246 } catch (FileNotFoundException e) { 247 return null; 248 } 249 250 Image img = sf.getIcon(false); 251 252 if (img != null) { 253 return new ImageIcon(img, sf.getFolderType()); 254 } else { 255 return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon"); 256 } 257 } 258 259 /** 260 * On Windows, a file can appear in multiple folders, other than its 261 * parent directory in the filesystem. Folder could for example be the 262 * "Desktop" folder which is not the same as file.getParentFile(). 263 * 264 * @param folder a <code>File</code> object representing a directory or special folder 265 * @param file a <code>File</code> object 266 * @return <code>true</code> if <code>folder</code> is a directory or special folder and contains <code>file</code>. 267 * @since 1.4 268 */ 269 public boolean isParent(File folder, File file) { 270 if (folder == null || file == null) { 271 return false; 272 } else if (folder instanceof ShellFolder) { 273 File parent = file.getParentFile(); 274 if (parent != null && parent.equals(folder)) { 275 return true; 276 } 277 File[] children = getFiles(folder, false); 278 for (File child : children) { 279 if (file.equals(child)) { 280 return true; 281 } 282 } 283 return false; 284 } else { 285 return folder.equals(file.getParentFile()); 286 } 287 } 288 289 /** 290 * 291 * @param parent a <code>File</code> object representing a directory or special folder 292 * @param fileName a name of a file or folder which exists in <code>parent</code> 293 * @return a File object. This is normally constructed with <code>new 294 * File(parent, fileName)</code> except when parent and child are both 295 * special folders, in which case the <code>File</code> is a wrapper containing 296 * a <code>ShellFolder</code> object. 297 * @since 1.4 298 */ 299 public File getChild(File parent, String fileName) { 300 if (parent instanceof ShellFolder) { 301 File[] children = getFiles(parent, false); 302 for (File child : children) { 303 if (child.getName().equals(fileName)) { 304 return child; 305 } 306 } 307 } 308 return createFileObject(parent, fileName); 309 } 310 311 312 /** 313 * Checks if <code>f</code> represents a real directory or file as opposed to a 314 * special folder such as <code>"Desktop"</code>. Used by UI classes to decide if 315 * a folder is selectable when doing directory choosing. 316 * 317 * @param f a <code>File</code> object 318 * @return <code>true</code> if <code>f</code> is a real file or directory. 319 * @since 1.4 320 */ 321 public boolean isFileSystem(File f) { 322 if (f instanceof ShellFolder) { 323 ShellFolder sf = (ShellFolder)f; 324 // Shortcuts to directories are treated as not being file system objects, 325 // so that they are never returned by JFileChooser. 326 return sf.isFileSystem() && !(sf.isLink() && sf.isDirectory()); 327 } else { 328 return true; 329 } 330 } 331 332 /** 333 * Creates a new folder with a default folder name. 334 * 335 * @param containingDir a {@code File} object denoting directory to contain the new folder 336 * @return a {@code File} object denoting the newly created folder 337 * @throws IOException if new folder could not be created 338 */ 339 public abstract File createNewFolder(File containingDir) throws IOException; 340 341 /** 342 * Returns whether a file is hidden or not. 343 * 344 * @param f a {@code File} object 345 * @return true if the given {@code File} denotes a hidden file 346 */ 347 public boolean isHiddenFile(File f) { 348 return f.isHidden(); 349 } 350 351 352 /** 353 * Is dir the root of a tree in the file system, such as a drive 354 * or partition. Example: Returns true for "C:\" on Windows 98. 355 * 356 * @param dir a <code>File</code> object representing a directory 357 * @return <code>true</code> if <code>f</code> is a root of a filesystem 358 * @see #isRoot 359 * @since 1.4 360 */ 361 public boolean isFileSystemRoot(File dir) { 362 return ShellFolder.isFileSystemRoot(dir); 363 } 364 365 /** 366 * Used by UI classes to decide whether to display a special icon 367 * for drives or partitions, e.g. a "hard disk" icon. 368 * 369 * The default implementation has no way of knowing, so always returns false. 370 * 371 * @param dir a directory 372 * @return <code>false</code> always 373 * @since 1.4 374 */ 375 public boolean isDrive(File dir) { 376 return false; 377 } 378 379 /** 380 * Used by UI classes to decide whether to display a special icon 381 * for a floppy disk. Implies isDrive(dir). 382 * 383 * The default implementation has no way of knowing, so always returns false. 384 * 385 * @param dir a directory 386 * @return <code>false</code> always 387 * @since 1.4 388 */ 389 public boolean isFloppyDrive(File dir) { 390 return false; 391 } 392 393 /** 394 * Used by UI classes to decide whether to display a special icon 395 * for a computer node, e.g. "My Computer" or a network server. 396 * 397 * The default implementation has no way of knowing, so always returns false. 398 * 399 * @param dir a directory 400 * @return <code>false</code> always 401 * @since 1.4 402 */ 403 public boolean isComputerNode(File dir) { 404 return ShellFolder.isComputerNode(dir); 405 } 406 407 408 /** 409 * Returns all root partitions on this system. For example, on 410 * Windows, this would be the "Desktop" folder, while on DOS this 411 * would be the A: through Z: drives. 412 * 413 * @return an array of {@code File} objects representing all root partitions 414 * on this system 415 */ 416 public File[] getRoots() { 417 // Don't cache this array, because filesystem might change 418 File[] roots = (File[])ShellFolder.get("roots"); 419 420 for (int i = 0; i < roots.length; i++) { 421 if (isFileSystemRoot(roots[i])) { 422 roots[i] = createFileSystemRoot(roots[i]); 423 } 424 } 425 return roots; 426 } 427 428 429 // Providing default implementations for the remaining methods 430 // because most OS file systems will likely be able to use this 431 // code. If a given OS can't, override these methods in its 432 // implementation. 433 434 /** 435 * Returns the home directory. 436 * @return the home directory 437 */ 438 public File getHomeDirectory() { 439 return createFileObject(System.getProperty("user.home")); 440 } 441 442 /** 443 * Return the user's default starting directory for the file chooser. 444 * 445 * @return a <code>File</code> object representing the default 446 * starting folder 447 * @since 1.4 448 */ 449 public File getDefaultDirectory() { 450 File f = (File)ShellFolder.get("fileChooserDefaultFolder"); 451 if (isFileSystemRoot(f)) { 452 f = createFileSystemRoot(f); 453 } 454 return f; 455 } 456 457 /** 458 * Returns a File object constructed in dir from the given filename. 459 * 460 * @param dir an abstract pathname denoting a directory 461 * @param filename a {@code String} representation of a pathname 462 * @return a {@code File} object created from {@code dir} and {@code filename} 463 */ 464 public File createFileObject(File dir, String filename) { 465 if(dir == null) { 466 return new File(filename); 467 } else { 468 return new File(dir, filename); 469 } 470 } 471 472 /** 473 * Returns a File object constructed from the given path string. 474 * 475 * @param path {@code String} representation of path 476 * @return a {@code File} object created from the given {@code path} 477 */ 478 public File createFileObject(String path) { 479 File f = new File(path); 480 if (isFileSystemRoot(f)) { 481 f = createFileSystemRoot(f); 482 } 483 return f; 484 } 485 486 487 /** 488 * Gets the list of shown (i.e. not hidden) files. 489 * 490 * @param dir the root directory of files to be returned 491 * @param useFileHiding determine if hidden files are returned 492 * @return an array of {@code File} objects representing files and 493 * directories in the given {@code dir}. It includes hidden 494 * files if {@code useFileHiding} is false. 495 */ 496 public File[] getFiles(File dir, boolean useFileHiding) { 497 List<File> files = new ArrayList<File>(); 498 499 // add all files in dir 500 if (!(dir instanceof ShellFolder)) { 501 try { 502 dir = getShellFolder(dir); 503 } catch (FileNotFoundException e) { 504 return new File[0]; 505 } 506 } 507 508 File[] names = ((ShellFolder) dir).listFiles(!useFileHiding); 509 510 if (names == null) { 511 return new File[0]; 512 } 513 514 for (File f : names) { 515 if (Thread.currentThread().isInterrupted()) { 516 break; 517 } 518 519 if (!(f instanceof ShellFolder)) { 520 if (isFileSystemRoot(f)) { 521 f = createFileSystemRoot(f); 522 } 523 try { 524 f = ShellFolder.getShellFolder(f); 525 } catch (FileNotFoundException e) { 526 // Not a valid file (wouldn't show in native file chooser) 527 // Example: C:\pagefile.sys 528 continue; 529 } catch (InternalError e) { 530 // Not a valid file (wouldn't show in native file chooser) 531 // Example C:\Winnt\Profiles\joe\history\History.IE5 532 continue; 533 } 534 } 535 if (!useFileHiding || !isHiddenFile(f)) { 536 files.add(f); 537 } 538 } 539 540 return files.toArray(new File[files.size()]); 541 } 542 543 544 545 /** 546 * Returns the parent directory of <code>dir</code>. 547 * @param dir the <code>File</code> being queried 548 * @return the parent directory of <code>dir</code>, or 549 * <code>null</code> if <code>dir</code> is <code>null</code> 550 */ 551 public File getParentDirectory(File dir) { 552 if (dir == null || !dir.exists()) { 553 return null; 554 } 555 556 ShellFolder sf; 557 558 try { 559 sf = getShellFolder(dir); 560 } catch (FileNotFoundException e) { 561 return null; 562 } 563 564 File psf = sf.getParentFile(); 565 566 if (psf == null) { 567 return null; 568 } 569 570 if (isFileSystem(psf)) { 571 File f = psf; 572 if (!f.exists()) { 573 // This could be a node under "Network Neighborhood". 574 File ppsf = psf.getParentFile(); 575 if (ppsf == null || !isFileSystem(ppsf)) { 576 // We're mostly after the exists() override for windows below. 577 f = createFileSystemRoot(f); 578 } 579 } 580 return f; 581 } else { 582 return psf; 583 } 584 } 585 586 /** 587 * Returns an array of files representing the values to show by default in 588 * the file chooser selector. 589 * 590 * @return an array of {@code File} objects. 591 * @throws SecurityException if the caller does not have necessary 592 * permissions 593 * @since 9 594 */ 595 public File[] getChooserComboBoxFiles() { 596 return (File[]) ShellFolder.get("fileChooserComboBoxFolders"); 597 } 598 599 /** 600 * Returns whether the specified file denotes a shell interpreted link which 601 * can be obtained by the {@link #getLinkLocation(File)}. 602 * 603 * @param file a file 604 * @return whether this is a link 605 * @throws NullPointerException if {@code file} equals {@code null} 606 * @throws SecurityException if the caller does not have necessary 607 * permissions 608 * @see #getLinkLocation(File) 609 * @since 9 610 */ 611 public boolean isLink(File file) { 612 if (file == null) { 613 throw new NullPointerException("file is null"); 614 } 615 try { 616 return ShellFolder.getShellFolder(file).isLink(); 617 } catch (FileNotFoundException e) { 618 return false; 619 } 620 } 621 622 /** 623 * Returns the regular file referenced by the specified link file if 624 * the specified file is a shell interpreted link. 625 * Returns {@code null} if the specified file is not 626 * a shell interpreted link. 627 * 628 * @param file a file 629 * @return the linked file or {@code null}. 630 * @throws FileNotFoundException if the linked file does not exist 631 * @throws NullPointerException if {@code file} equals {@code null} 632 * @throws SecurityException if the caller does not have necessary 633 * permissions 634 * @since 9 635 */ 636 public File getLinkLocation(File file) throws FileNotFoundException { 637 if (file == null) { 638 throw new NullPointerException("file is null"); 639 } 640 ShellFolder shellFolder; 641 try { 642 shellFolder = ShellFolder.getShellFolder(file); 643 } catch (FileNotFoundException e) { 644 return null; 645 } 646 return shellFolder.isLink() ? shellFolder.getLinkLocation() : null; 647 } 648 649 /** 650 * Throws {@code FileNotFoundException} if file not found or current thread was interrupted 651 */ 652 ShellFolder getShellFolder(File f) throws FileNotFoundException { 653 if (!(f instanceof ShellFolder) && !(f instanceof FileSystemRoot) && isFileSystemRoot(f)) { 654 f = createFileSystemRoot(f); 655 } 656 657 try { 658 return ShellFolder.getShellFolder(f); 659 } catch (InternalError e) { 660 System.err.println("FileSystemView.getShellFolder: f="+f); 661 e.printStackTrace(); 662 return null; 663 } 664 } 665 666 /** 667 * Creates a new <code>File</code> object for <code>f</code> with correct 668 * behavior for a file system root directory. 669 * 670 * @param f a <code>File</code> object representing a file system root 671 * directory, for example "/" on Unix or "C:\" on Windows. 672 * @return a new <code>File</code> object 673 * @since 1.4 674 */ 675 protected File createFileSystemRoot(File f) { 676 return new FileSystemRoot(f); 677 } 678 679 @SuppressWarnings("serial") // Same-version serialization only 680 static class FileSystemRoot extends File { 681 public FileSystemRoot(File f) { 682 super(f,""); 683 } 684 685 public FileSystemRoot(String s) { 686 super(s); 687 } 688 689 public boolean isDirectory() { 690 return true; 691 } 692 693 public String getName() { 694 return getPath(); 695 } 696 } 697 } 698 699 /** 700 * FileSystemView that handles some specific unix-isms. 701 */ 702 class UnixFileSystemView extends FileSystemView { 703 704 private static final String newFolderString = 705 UIManager.getString("FileChooser.other.newFolder"); 706 private static final String newFolderNextString = 707 UIManager.getString("FileChooser.other.newFolder.subsequent"); 708 709 /** 710 * Creates a new folder with a default folder name. 711 */ 712 public File createNewFolder(File containingDir) throws IOException { 713 if(containingDir == null) { 714 throw new IOException("Containing directory is null:"); 715 } 716 File newFolder; 717 // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE. 718 newFolder = createFileObject(containingDir, newFolderString); 719 int i = 1; 720 while (newFolder.exists() && i < 100) { 721 newFolder = createFileObject(containingDir, MessageFormat.format( 722 newFolderNextString, i)); 723 i++; 724 } 725 726 if(newFolder.exists()) { 727 throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); 728 } else { 729 if(!newFolder.mkdirs()) { 730 throw new IOException(newFolder.getAbsolutePath()); 731 } 732 } 733 734 return newFolder; 735 } 736 737 public boolean isFileSystemRoot(File dir) { 738 return dir != null && dir.getAbsolutePath().equals("/"); 739 } 740 741 public boolean isDrive(File dir) { 742 return isFloppyDrive(dir); 743 } 744 745 public boolean isFloppyDrive(File dir) { 746 // Could be looking at the path for Solaris, but wouldn't be reliable. 747 // For example: 748 // return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy")); 749 return false; 750 } 751 752 public boolean isComputerNode(File dir) { 753 if (dir != null) { 754 String parent = dir.getParent(); 755 if (parent != null && parent.equals("/net")) { 756 return true; 757 } 758 } 759 return false; 760 } 761 } 762 763 764 /** 765 * FileSystemView that handles some specific windows concepts. 766 */ 767 class WindowsFileSystemView extends FileSystemView { 768 769 private static final String newFolderString = 770 UIManager.getString("FileChooser.win32.newFolder"); 771 private static final String newFolderNextString = 772 UIManager.getString("FileChooser.win32.newFolder.subsequent"); 773 774 public Boolean isTraversable(File f) { 775 return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory()); 776 } 777 778 public File getChild(File parent, String fileName) { 779 if (fileName.startsWith("\\") 780 && !fileName.startsWith("\\\\") 781 && isFileSystem(parent)) { 782 783 //Path is relative to the root of parent's drive 784 String path = parent.getAbsolutePath(); 785 if (path.length() >= 2 786 && path.charAt(1) == ':' 787 && Character.isLetter(path.charAt(0))) { 788 789 return createFileObject(path.substring(0, 2) + fileName); 790 } 791 } 792 return super.getChild(parent, fileName); 793 } 794 795 /** 796 * Type description for a file, directory, or folder as it would be displayed in 797 * a system file browser. Example from Windows: the "Desktop" folder 798 * is described as "Desktop". 799 * 800 * The Windows implementation gets information from the ShellFolder class. 801 */ 802 public String getSystemTypeDescription(File f) { 803 if (f == null) { 804 return null; 805 } 806 807 try { 808 return getShellFolder(f).getFolderType(); 809 } catch (FileNotFoundException e) { 810 return null; 811 } 812 } 813 814 /** 815 * @return the Desktop folder. 816 */ 817 public File getHomeDirectory() { 818 File[] roots = getRoots(); 819 return (roots.length == 0) ? null : roots[0]; 820 } 821 822 /** 823 * Creates a new folder with a default folder name. 824 */ 825 public File createNewFolder(File containingDir) throws IOException { 826 if(containingDir == null) { 827 throw new IOException("Containing directory is null:"); 828 } 829 // Using NT's default folder name 830 File newFolder = createFileObject(containingDir, newFolderString); 831 int i = 2; 832 while (newFolder.exists() && i < 100) { 833 newFolder = createFileObject(containingDir, MessageFormat.format( 834 newFolderNextString, i)); 835 i++; 836 } 837 838 if(newFolder.exists()) { 839 throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); 840 } else { 841 if(!newFolder.mkdirs()) { 842 throw new IOException(newFolder.getAbsolutePath()); 843 } 844 } 845 846 return newFolder; 847 } 848 849 public boolean isDrive(File dir) { 850 return isFileSystemRoot(dir); 851 } 852 853 public boolean isFloppyDrive(final File dir) { 854 String path = AccessController.doPrivileged(new PrivilegedAction<String>() { 855 public String run() { 856 return dir.getAbsolutePath(); 857 } 858 }); 859 860 return path != null && (path.equals("A:\\") || path.equals("B:\\")); 861 } 862 863 /** 864 * Returns a File object constructed from the given path string. 865 */ 866 public File createFileObject(String path) { 867 // Check for missing backslash after drive letter such as "C:" or "C:filename" 868 if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) { 869 if (path.length() == 2) { 870 path += "\\"; 871 } else if (path.charAt(2) != '\\') { 872 path = path.substring(0, 2) + "\\" + path.substring(2); 873 } 874 } 875 return super.createFileObject(path); 876 } 877 878 @SuppressWarnings("serial") // anonymous class 879 protected File createFileSystemRoot(File f) { 880 // Problem: Removable drives on Windows return false on f.exists() 881 // Workaround: Override exists() to always return true. 882 return new FileSystemRoot(f) { 883 public boolean exists() { 884 return true; 885 } 886 }; 887 } 888 889 } 890 891 /** 892 * Fallthrough FileSystemView in case we can't determine the OS. 893 */ 894 class GenericFileSystemView extends FileSystemView { 895 896 private static final String newFolderString = 897 UIManager.getString("FileChooser.other.newFolder"); 898 899 /** 900 * Creates a new folder with a default folder name. 901 */ 902 public File createNewFolder(File containingDir) throws IOException { 903 if(containingDir == null) { 904 throw new IOException("Containing directory is null:"); 905 } 906 // Using NT's default folder name 907 File newFolder = createFileObject(containingDir, newFolderString); 908 909 if(newFolder.exists()) { 910 throw new IOException("Directory already exists:" + newFolder.getAbsolutePath()); 911 } else { 912 if(!newFolder.mkdirs()) { 913 throw new IOException(newFolder.getAbsolutePath()); 914 } 915 } 916 return newFolder; 917 } 918 919 }