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 }