KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > filechooser > FileSystemView


1 /*
2  * @(#)FileSystemView.java 1.46 04/04/27
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.filechooser;
9
10
11 import javax.swing.event.*;
12 import javax.swing.*;
13
14 import java.awt.Image JavaDoc;
15 import java.io.File JavaDoc;
16 import java.io.FileFilter JavaDoc;
17 import java.io.FilenameFilter JavaDoc;
18 import java.io.FileNotFoundException JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.text.MessageFormat JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.Vector JavaDoc;
25 import java.beans.PropertyChangeListener JavaDoc;
26 import java.beans.PropertyChangeEvent JavaDoc;
27
28
29 import java.lang.reflect.*;
30
31 import sun.awt.shell.*;
32
33 /**
34  * FileSystemView is JFileChooser's gateway to the
35  * file system. Since the JDK1.1 File API doesn't allow
36  * access to such information as root partitions, file type
37  * information, or hidden file bits, this class is designed
38  * to intuit as much OS-specific file system information as
39  * possible.
40  *
41  * <p>
42  *
43  * Java Licensees may want to provide a different implementation of
44  * FileSystemView to better handle a given operating system.
45  *
46  * @version 1.46 04/27/04
47  * @author Jeff Dinkins
48  */

49
50 // PENDING(jeff) - need to provide a specification for
51
// how Mac/OS2/BeOS/etc file systems can modify FileSystemView
52
// to handle their particular type of file system.
53

54 public abstract class FileSystemView {
55
56     static FileSystemView JavaDoc windowsFileSystemView = null;
57     static FileSystemView JavaDoc unixFileSystemView = null;
58     //static FileSystemView macFileSystemView = null;
59
static FileSystemView JavaDoc genericFileSystemView = null;
60     static boolean useSystemExtensionsHiding = false;
61
62     public static FileSystemView JavaDoc getFileSystemView() {
63         useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding");
64         UIManager.addPropertyChangeListener(new PropertyChangeListener JavaDoc() {
65             public void propertyChange(PropertyChangeEvent JavaDoc e) {
66                if (e.getPropertyName().equals("lookAndFeel")) {
67                    useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding");
68                }
69             }
70         });
71
72     if(File.separatorChar == '\\') {
73         if(windowsFileSystemView == null) {
74         windowsFileSystemView = new WindowsFileSystemView();
75         }
76         return windowsFileSystemView;
77     }
78
79     if(File.separatorChar == '/') {
80         if(unixFileSystemView == null) {
81         unixFileSystemView = new UnixFileSystemView();
82         }
83         return unixFileSystemView;
84     }
85
86     // if(File.separatorChar == ':') {
87
// if(macFileSystemView == null) {
88
// macFileSystemView = new MacFileSystemView();
89
// }
90
// return macFileSystemView;
91
//}
92

93     if(genericFileSystemView == null) {
94         genericFileSystemView = new GenericFileSystemView();
95     }
96     return genericFileSystemView;
97     }
98
99     /**
100      * Determines if the given file is a root in the navigatable tree(s).
101      * Examples: Windows 98 has one root, the Desktop folder. DOS has one root
102      * per drive letter, <code>C:\</code>, <code>D:\</code>, etc. Unix has one root,
103      * the <code>"/"</code> directory.
104      *
105      * The default implementation gets information from the <code>ShellFolder</code> class.
106      *
107      * @param f a <code>File</code> object representing a directory
108      * @return <code>true</code> if <code>f</code> is a root in the navigatable tree.
109      * @see #isFileSystemRoot
110      */

111     public boolean isRoot(File JavaDoc f) {
112     if (f == null || !f.isAbsolute()) {
113         return false;
114     }
115
116     File JavaDoc[] roots = getRoots();
117     for (int i = 0; i < roots.length; i++) {
118         if (roots[i].equals(f)) {
119         return true;
120         }
121     }
122     return false;
123     }
124
125     /**
126      * Returns true if the file (directory) can be visited.
127      * Returns false if the directory cannot be traversed.
128      *
129      * @param f the <code>File</code>
130      * @return <code>true</code> if the file/directory can be traversed, otherwise <code>false</code>
131      * @see JFileChooser#isTraversable
132      * @see FileView#isTraversable
133      */

134     public Boolean JavaDoc isTraversable(File JavaDoc f) {
135     return Boolean.valueOf(f.isDirectory());
136     }
137
138     /**
139      * Name of a file, directory, or folder as it would be displayed in
140      * a system file browser. Example from Windows: the "M:\" directory
141      * displays as "CD-ROM (M:)"
142      *
143      * The default implementation gets information from the ShellFolder class.
144      *
145      * @param f a <code>File</code> object
146      * @return the file name as it would be displayed by a native file chooser
147      * @see JFileChooser#getName
148      */

149     public String JavaDoc getSystemDisplayName(File JavaDoc f) {
150     String JavaDoc name = null;
151     if (f != null) {
152         name = f.getName();
153         if (!name.equals("..") && !name.equals(".") &&
154                 (useSystemExtensionsHiding ||
155                  !isFileSystem(f) ||
156                  isFileSystemRoot(f)) &&
157         ((f instanceof ShellFolder) ||
158          f.exists())) {
159
160         name = getShellFolder(f).getDisplayName();
161         if (name == null || name.length() == 0) {
162             name = f.getPath(); // e.g. "/"
163
}
164         }
165     }
166     return name;
167     }
168
169     /**
170      * Type description for a file, directory, or folder as it would be displayed in
171      * a system file browser. Example from Windows: the "Desktop" folder
172      * is desribed as "Desktop".
173      *
174      * Override for platforms with native ShellFolder implementations.
175      *
176      * @param f a <code>File</code> object
177      * @return the file type description as it would be displayed by a native file chooser
178      * or null if no native information is available.
179      * @see JFileChooser#getTypeDescription
180      */

181     public String JavaDoc getSystemTypeDescription(File JavaDoc f) {
182     return null;
183     }
184
185     /**
186      * Icon for a file, directory, or folder as it would be displayed in
187      * a system file browser. Example from Windows: the "M:\" directory
188      * displays a CD-ROM icon.
189      *
190      * The default implementation gets information from the ShellFolder class.
191      *
192      * @param f a <code>File</code> object
193      * @return an icon as it would be displayed by a native file chooser
194      * @see JFileChooser#getIcon
195      */

196     public Icon getSystemIcon(File JavaDoc f) {
197     if (f != null) {
198         ShellFolder sf = getShellFolder(f);
199         Image JavaDoc img = sf.getIcon(false);
200         if (img != null) {
201         return new ImageIcon(img, sf.getFolderType());
202         } else {
203         return UIManager.getIcon(f.isDirectory() ? "FileView.directoryIcon" : "FileView.fileIcon");
204         }
205     } else {
206         return null;
207     }
208     }
209
210     /**
211      * On Windows, a file can appear in multiple folders, other than its
212      * parent directory in the filesystem. Folder could for example be the
213      * "Desktop" folder which is not the same as file.getParentFile().
214      *
215      * @param folder a <code>File</code> object repesenting a directory or special folder
216      * @param file a <code>File</code> object
217      * @return <code>true</code> if <code>folder</code> is a directory or special folder and contains <code>file</code>.
218      */

219     public boolean isParent(File JavaDoc folder, File JavaDoc file) {
220     if (folder == null || file == null) {
221         return false;
222     } else if (folder instanceof ShellFolder) {
223         File JavaDoc parent = file.getParentFile();
224         if (parent != null && parent.equals(folder)) {
225             return true;
226         }
227         File JavaDoc[] children = getFiles(folder, false);
228         for (int i = 0; i < children.length; i++) {
229         if (file.equals(children[i])) {
230             return true;
231         }
232         }
233         return false;
234     } else {
235         return folder.equals(file.getParentFile());
236     }
237     }
238
239     /**
240      *
241      * @param parent a <code>File</code> object repesenting a directory or special folder
242      * @param fileName a name of a file or folder which exists in <code>parent</code>
243      * @return a File object. This is normally constructed with <code>new
244      * File(parent, fileName)</code> except when parent and child are both
245      * special folders, in which case the <code>File</code> is a wrapper containing
246      * a <code>ShellFolder</code> object.
247      */

248     public File JavaDoc getChild(File JavaDoc parent, String JavaDoc fileName) {
249     if (parent instanceof ShellFolder) {
250         File JavaDoc[] children = getFiles(parent, false);
251         for (int i = 0; i < children.length; i++) {
252         if (children[i].getName().equals(fileName)) {
253             return children[i];
254         }
255         }
256     }
257     return createFileObject(parent, fileName);
258     }
259
260
261     /**
262      * Checks if <code>f</code> represents a real directory or file as opposed to a
263      * special folder such as <code>"Desktop"</code>. Used by UI classes to decide if
264      * a folder is selectable when doing directory choosing.
265      *
266      * @param f a <code>File</code> object
267      * @return <code>true</code> if <code>f</code> is a real file or directory.
268      */

269     public boolean isFileSystem(File JavaDoc f) {
270     if (f instanceof ShellFolder) {
271         ShellFolder sf = (ShellFolder)f;
272         // Shortcuts to directories are treated as not being file system objects,
273
// so that they are never returned by JFileChooser.
274
return sf.isFileSystem() && !(sf.isLink() && sf.isDirectory());
275     } else {
276         return true;
277     }
278     }
279
280     /**
281      * Creates a new folder with a default folder name.
282      */

283     public abstract File JavaDoc createNewFolder(File JavaDoc containingDir) throws IOException JavaDoc;
284
285     /**
286      * Returns whether a file is hidden or not.
287      */

288     public boolean isHiddenFile(File JavaDoc f) {
289     return f.isHidden();
290     }
291
292
293     /**
294      * Is dir the root of a tree in the file system, such as a drive
295      * or partition. Example: Returns true for "C:\" on Windows 98.
296      *
297      * @param f a <code>File</code> object representing a directory
298      * @return <code>true</code> if <code>f</code> is a root of a filesystem
299      * @see #isRoot
300      */

301     public boolean isFileSystemRoot(File JavaDoc dir) {
302     return ShellFolder.isFileSystemRoot(dir);
303     }
304
305     /**
306      * Used by UI classes to decide whether to display a special icon
307      * for drives or partitions, e.g. a "hard disk" icon.
308      *
309      * The default implementation has no way of knowing, so always returns false.
310      *
311      * @param dir a directory
312      * @return <code>false</code> always
313      */

314     public boolean isDrive(File JavaDoc dir) {
315     return false;
316     }
317
318     /**
319      * Used by UI classes to decide whether to display a special icon
320      * for a floppy disk. Implies isDrive(dir).
321      *
322      * The default implementation has no way of knowing, so always returns false.
323      *
324      * @param dir a directory
325      * @return <code>false</code> always
326      */

327     public boolean isFloppyDrive(File JavaDoc dir) {
328     return false;
329     }
330
331     /**
332      * Used by UI classes to decide whether to display a special icon
333      * for a computer node, e.g. "My Computer" or a network server.
334      *
335      * The default implementation has no way of knowing, so always returns false.
336      *
337      * @param dir a directory
338      * @return <code>false</code> always
339      */

340     public boolean isComputerNode(File JavaDoc dir) {
341     return ShellFolder.isComputerNode(dir);
342     }
343
344
345     /**
346      * Returns all root partitions on this system. For example, on
347      * Windows, this would be the "Desktop" folder, while on DOS this
348      * would be the A: through Z: drives.
349      */

350     public File JavaDoc[] getRoots() {
351     // Don't cache this array, because filesystem might change
352
File JavaDoc[] roots = (File JavaDoc[])ShellFolder.get("roots");
353
354     for (int i = 0; i < roots.length; i++) {
355         if (isFileSystemRoot(roots[i])) {
356         roots[i] = createFileSystemRoot(roots[i]);
357         }
358     }
359     return roots;
360     }
361
362
363     // Providing default implementations for the remaining methods
364
// because most OS file systems will likely be able to use this
365
// code. If a given OS can't, override these methods in its
366
// implementation.
367

368     public File JavaDoc getHomeDirectory() {
369     return createFileObject(System.getProperty("user.home"));
370     }
371
372     /**
373      * Return the user's default starting directory for the file chooser.
374      *
375      * @return a <code>File</code> object representing the default
376      * starting folder
377      */

378     public File JavaDoc getDefaultDirectory() {
379     File JavaDoc f = (File JavaDoc)ShellFolder.get("fileChooserDefaultFolder");
380     if (isFileSystemRoot(f)) {
381         f = createFileSystemRoot(f);
382     }
383     return f;
384     }
385
386     /**
387      * Returns a File object constructed in dir from the given filename.
388      */

389     public File JavaDoc createFileObject(File JavaDoc dir, String JavaDoc filename) {
390     if(dir == null) {
391         return new File JavaDoc(filename);
392     } else {
393         return new File JavaDoc(dir, filename);
394     }
395     }
396
397     /**
398      * Returns a File object constructed from the given path string.
399      */

400     public File JavaDoc createFileObject(String JavaDoc path) {
401     File JavaDoc f = new File JavaDoc(path);
402     if (isFileSystemRoot(f)) {
403         f = createFileSystemRoot(f);
404     }
405     return f;
406     }
407
408
409     /**
410      * Gets the list of shown (i.e. not hidden) files.
411      */

412     public File JavaDoc[] getFiles(File JavaDoc dir, boolean useFileHiding) {
413     Vector JavaDoc files = new Vector JavaDoc();
414
415
416     // add all files in dir
417
File JavaDoc[] names;
418         if (!(dir instanceof ShellFolder)) {
419         dir = getShellFolder(dir);
420         }
421
422         names = ((ShellFolder)dir).listFiles(!useFileHiding);
423     File JavaDoc f;
424
425     int nameCount = (names == null) ? 0 : names.length;
426     for (int i = 0; i < nameCount; i++) {
427         if (Thread.currentThread().isInterrupted()) {
428         break;
429         }
430         f = names[i];
431         if (!(f instanceof ShellFolder)) {
432         if (isFileSystemRoot(f)) {
433             f = createFileSystemRoot(f);
434         }
435         try {
436             f = ShellFolder.getShellFolder(f);
437         } catch (FileNotFoundException JavaDoc e) {
438             // Not a valid file (wouldn't show in native file chooser)
439
// Example: C:\pagefile.sys
440
continue;
441         } catch (InternalError JavaDoc e) {
442             // Not a valid file (wouldn't show in native file chooser)
443
// Example C:\Winnt\Profiles\joe\history\History.IE5
444
continue;
445         }
446         }
447         if (!useFileHiding || !isHiddenFile(f)) {
448         files.addElement(f);
449         }
450     }
451
452     return (File JavaDoc[])files.toArray(new File JavaDoc[files.size()]);
453     }
454
455
456
457     /**
458      * Returns the parent directory of <code>dir</code>.
459      * @param dir the <code>File</code> being queried
460      * @return the parent directory of <code>dir</code>, or
461      * <code>null</code> if <code>dir</code> is <code>null</code>
462      */

463     public File JavaDoc getParentDirectory(File JavaDoc dir) {
464     if (dir != null && dir.exists()) {
465         ShellFolder sf = getShellFolder(dir);
466         File JavaDoc psf = sf.getParentFile();
467         if (psf != null) {
468         if (isFileSystem(psf)) {
469             File JavaDoc f = psf;
470             if (f != null && !f.exists()) {
471             // This could be a node under "Network Neighborhood".
472
File JavaDoc ppsf = psf.getParentFile();
473             if (ppsf == null || !isFileSystem(ppsf)) {
474                 // We're mostly after the exists() override for windows below.
475
f = createFileSystemRoot(f);
476             }
477             }
478             return f;
479         } else {
480             return psf;
481         }
482         }
483     }
484     return null;
485     }
486
487     ShellFolder getShellFolder(File JavaDoc f) {
488     if (!(f instanceof ShellFolder)
489         && !(f instanceof FileSystemRoot)
490         && isFileSystemRoot(f)) {
491
492         f = createFileSystemRoot(f);
493     }
494     try {
495         return ShellFolder.getShellFolder(f);
496     } catch (FileNotFoundException JavaDoc e) {
497         System.err.println("FileSystemView.getShellFolder: f="+f);
498         e.printStackTrace();
499         return null;
500     } catch (InternalError JavaDoc e) {
501         System.err.println("FileSystemView.getShellFolder: f="+f);
502         e.printStackTrace();
503         return null;
504     }
505     }
506
507     /**
508      * Creates a new <code>File</code> object for <code>f</code> with correct
509      * behavior for a file system root directory.
510      *
511      * @param f a <code>File</code> object representing a file system root
512      * directory, for example "/" on Unix or "C:\" on Windows.
513      * @return a new <code>File</code> object
514      */

515     protected File JavaDoc createFileSystemRoot(File JavaDoc f) {
516     return new FileSystemRoot(f);
517     }
518
519
520
521
522     static class FileSystemRoot extends File JavaDoc {
523     public FileSystemRoot(File JavaDoc f) {
524         super(f,"");
525     }
526
527     public FileSystemRoot(String JavaDoc s) {
528         super(s);
529     }
530
531     public boolean isDirectory() {
532         return true;
533     }
534
535     public String JavaDoc getName() {
536         return getPath();
537     }
538     }
539 }
540
541 /**
542  * FileSystemView that handles some specific unix-isms.
543  */

544 class UnixFileSystemView extends FileSystemView JavaDoc {
545
546     private static final String JavaDoc newFolderString =
547             UIManager.getString("FileChooser.other.newFolder");
548     private static final String JavaDoc newFolderNextString =
549             UIManager.getString("FileChooser.other.newFolder.subsequent");
550
551     /**
552      * Creates a new folder with a default folder name.
553      */

554     public File JavaDoc createNewFolder(File JavaDoc containingDir) throws IOException JavaDoc {
555     if(containingDir == null) {
556         throw new IOException JavaDoc("Containing directory is null:");
557     }
558     File JavaDoc newFolder = null;
559     // Unix - using OpenWindows' default folder name. Can't find one for Motif/CDE.
560
newFolder = createFileObject(containingDir, newFolderString);
561     int i = 1;
562     while (newFolder.exists() && (i < 100)) {
563         newFolder = createFileObject(containingDir, MessageFormat.format(
564                     newFolderNextString, new Object JavaDoc[] { new Integer JavaDoc(i) }));
565         i++;
566     }
567
568     if(newFolder.exists()) {
569         throw new IOException JavaDoc("Directory already exists:" + newFolder.getAbsolutePath());
570     } else {
571         newFolder.mkdirs();
572     }
573
574     return newFolder;
575     }
576
577     public boolean isFileSystemRoot(File JavaDoc dir) {
578     return (dir != null && dir.getAbsolutePath().equals("/"));
579     }
580
581     public boolean isDrive(File JavaDoc dir) {
582     if (isFloppyDrive(dir)) {
583         return true;
584     } else {
585         return false;
586     }
587     }
588
589     public boolean isFloppyDrive(File JavaDoc dir) {
590     // Could be looking at the path for Solaris, but wouldn't be reliable.
591
// For example:
592
// return (dir != null && dir.getAbsolutePath().toLowerCase().startsWith("/floppy"));
593
return false;
594     }
595
596     public boolean isComputerNode(File JavaDoc dir) {
597     if (dir != null) {
598         String JavaDoc parent = dir.getParent();
599         if (parent != null && parent.equals("/net")) {
600         return true;
601         }
602     }
603     return false;
604     }
605 }
606
607
608 /**
609  * FileSystemView that handles some specific windows concepts.
610  */

611 class WindowsFileSystemView extends FileSystemView JavaDoc {
612
613     private static final String JavaDoc newFolderString =
614             UIManager.getString("FileChooser.win32.newFolder");
615     private static final String JavaDoc newFolderNextString =
616             UIManager.getString("FileChooser.win32.newFolder.subsequent");
617
618     public Boolean JavaDoc isTraversable(File JavaDoc f) {
619     return Boolean.valueOf(isFileSystemRoot(f) || isComputerNode(f) || f.isDirectory());
620     }
621
622     public File JavaDoc getChild(File JavaDoc parent, String JavaDoc fileName) {
623     if (fileName.startsWith("\\")
624         && !(fileName.startsWith("\\\\"))
625         && isFileSystem(parent)) {
626
627         //Path is relative to the root of parent's drive
628
String JavaDoc path = parent.getAbsolutePath();
629         if (path.length() >= 2
630         && path.charAt(1) == ':'
631         && Character.isLetter(path.charAt(0))) {
632
633         return createFileObject(path.substring(0, 2) + fileName);
634         }
635     }
636     return super.getChild(parent, fileName);
637     }
638
639     /**
640      * Type description for a file, directory, or folder as it would be displayed in
641      * a system file browser. Example from Windows: the "Desktop" folder
642      * is desribed as "Desktop".
643      *
644      * The Windows implementation gets information from the ShellFolder class.
645      */

646     public String JavaDoc getSystemTypeDescription(File JavaDoc f) {
647     if (f != null) {
648         return getShellFolder(f).getFolderType();
649     } else {
650         return null;
651     }
652     }
653
654     /**
655      * @return the Desktop folder.
656      */

657     public File JavaDoc getHomeDirectory() {
658     return getRoots()[0];
659     }
660
661     /**
662      * Creates a new folder with a default folder name.
663      */

664     public File JavaDoc createNewFolder(File JavaDoc containingDir) throws IOException JavaDoc {
665     if(containingDir == null) {
666         throw new IOException JavaDoc("Containing directory is null:");
667     }
668     File JavaDoc newFolder = null;
669     // Using NT's default folder name
670
newFolder = createFileObject(containingDir, newFolderString);
671     int i = 2;
672     while (newFolder.exists() && (i < 100)) {
673         newFolder = createFileObject(containingDir, MessageFormat.format(
674                 newFolderNextString, new Object JavaDoc[] { new Integer JavaDoc(i) }));
675         i++;
676     }
677
678     if(newFolder.exists()) {
679         throw new IOException JavaDoc("Directory already exists:" + newFolder.getAbsolutePath());
680     } else {
681         newFolder.mkdirs();
682     }
683
684     return newFolder;
685     }
686
687     public boolean isDrive(File JavaDoc dir) {
688     return isFileSystemRoot(dir);
689     }
690
691     public boolean isFloppyDrive(File JavaDoc dir) {
692     String JavaDoc path = dir.getAbsolutePath();
693     return (path != null && (path.equals("A:\\") || path.equals("B:\\")));
694     }
695
696     /**
697      * Returns a File object constructed from the given path string.
698      */

699     public File JavaDoc createFileObject(String JavaDoc path) {
700     // Check for missing backslash after drive letter such as "C:" or "C:filename"
701
if (path.length() >= 2 && path.charAt(1) == ':' && Character.isLetter(path.charAt(0))) {
702         if (path.length() == 2) {
703         path += "\\";
704         } else if (path.charAt(2) != '\\') {
705         path = path.substring(0, 2) + "\\" + path.substring(2);
706         }
707     }
708     return super.createFileObject(path);
709     }
710
711     protected File JavaDoc createFileSystemRoot(File JavaDoc f) {
712     // Problem: Removable drives on Windows return false on f.exists()
713
// Workaround: Override exists() to always return true.
714
return new FileSystemRoot(f) {
715         public boolean exists() {
716         return true;
717         }
718     };
719     }
720
721 }
722
723 /**
724  * Fallthrough FileSystemView in case we can't determine the OS.
725  */

726 class GenericFileSystemView extends FileSystemView JavaDoc {
727
728     private static final String JavaDoc newFolderString =
729             UIManager.getString("FileChooser.other.newFolder");
730
731     /**
732      * Creates a new folder with a default folder name.
733      */

734     public File JavaDoc createNewFolder(File JavaDoc containingDir) throws IOException JavaDoc {
735     if(containingDir == null) {
736         throw new IOException JavaDoc("Containing directory is null:");
737     }
738     File JavaDoc newFolder = null;
739     // Using NT's default folder name
740
newFolder = createFileObject(containingDir, newFolderString);
741
742     if(newFolder.exists()) {
743         throw new IOException JavaDoc("Directory already exists:" + newFolder.getAbsolutePath());
744     } else {
745         newFolder.mkdirs();
746     }
747
748     return newFolder;
749     }
750
751 }
752
Popular Tags