KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > schlichtherle > io > swing > FileSystemView


1 /*
2  * FileSystemView.java
3  *
4  * Created on 28. November 2004, 13:26
5  */

6 /*
7  * Copyright 2005-2006 Schlichtherle IT Services
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */

21
22 package de.schlichtherle.io.swing;
23
24 import de.schlichtherle.io.*;
25 import de.schlichtherle.io.File;
26
27 import java.io.*;
28 import java.text.*;
29 import java.util.*;
30
31 import javax.swing.*;
32
33 /**
34  * This is the custom filesystem view required to browse archive files
35  * like directories with a JFileChooser.
36  * It is also used by
37  * {@link de.schlichtherle.io.swing.tree.FileTreeCellRenderer}
38  * to render files and directories in a
39  * {@link de.schlichtherle.io.swing.JFileTree}.
40  *
41  * @author Christian Schlichtherle
42  * @version @version@
43  */

44 //
45
// Unfortunately this is a pretty ugly piece of code.
46
// The reason for this is the completely broken design of the genuine
47
// JFileChooser, FileSystemView, FileView, ShellFolder and BasicFileChooserUI
48
// classes.
49
// The FileSystemView uses a lot of "instanceof" runtime type detections
50
// in conjunction with Sun's proprietory (and platform dependent) ShellFolder
51
// class, which subclasses java.io.File.
52
// Other classes like BasicFileChooserUI also rely on the use of the
53
// ShellFolder class, which they really shouldn't.
54
// The use of the ShellFolder class is also the sole reason for the existence
55
// of the file delegate property in de.schlichtherle.io.File.
56
// For many methods in this class, we need to pass in the delegate to the
57
// superclass implementation in order for the JFileChooser to work as expected.
58
//
59
// Dear Sun: Please COMPLETELY redesign the JFileChooser, FileSystemView,
60
// FileView and ShellFolder classes. A little bit of fixing will not do the
61
// job!
62
// My primary recommendation would be to define clear responsibilities for
63
// each of the redesigned classes: Most importantly, all (meta) properties of
64
// a file (like its name, icon, description, etc.) should be clearly located
65
// in ONE class and whoever uses this should rely on polymorphism rather than
66
// instanceof conditionals.
67
// Finally, please put your new design to test with browsing a virtual file
68
// system (like TrueZIP provides) - the current JFileChooser is just not able
69
// to do this right.
70
//
71
public class FileSystemView extends AbstractFileSystemView {
72
73     private static final String JavaDoc CLASS_NAME
74             = "de/schlichtherle/io/swing/FileSystemView".replace('/', '.'); // support code obfuscation!
75
private static final ResourceBundle resources
76             = ResourceBundle.getBundle(CLASS_NAME);
77
78     private static FileSystemView defaultView = new FileSystemView(
79             javax.swing.filechooser.FileSystemView.getFileSystemView(),
80             null);
81
82     public final static javax.swing.filechooser.FileSystemView JavaDoc getFileSystemView() {
83         return getFileSystemView(null);
84     }
85
86     public final static javax.swing.filechooser.FileSystemView JavaDoc getFileSystemView(
87             ArchiveDetector archiveDetector) {
88         return archiveDetector != null
89             ? new FileSystemView(
90                 javax.swing.filechooser.FileSystemView.getFileSystemView(),
91                 archiveDetector)
92             : defaultView;
93     }
94
95     /** Maybe null - uses default then. **/
96     private ArchiveDetector archiveDetector;
97
98     private FileSystemView(
99             javax.swing.filechooser.FileSystemView JavaDoc delegate,
100             ArchiveDetector archiveDetector) {
101         super(delegate);
102         this.archiveDetector = archiveDetector;
103     }
104
105     /**
106      * Returns a valid archive detector to use with this class.
107      * If no archive detector has been explicitly set for this file system
108      * view or the archive detector has been set to <code>null</code>,
109      * then {@link de.schlichtherle.io.File#getDefaultArchiveDetector} is
110      * returned.
111      */

112     public ArchiveDetector getArchiveDetector() {
113         return archiveDetector != null
114             ? archiveDetector
115             : File.getDefaultArchiveDetector();
116     }
117
118     /**
119      * Sets the archive detector to use within this class.
120      *
121      * @param archiveDetector The archive detector to use.
122      * May be <code>null</code> to indicate that
123      * {@link de.schlichtherle.io.File#getDefaultArchiveDetector}
124      * should be used.
125      */

126     public void setArchiveDetector(ArchiveDetector archiveDetector) {
127         this.archiveDetector = archiveDetector;
128     }
129
130     /**
131      * Wraps the given file in an archive enabled file.
132      */

133     protected File wrap(final java.io.File JavaDoc file) {
134         if (file == null)
135             return null;
136         else if (file instanceof File)
137             return (File) file;
138         else
139             return getArchiveDetector().createFile(file);
140     }
141
142     /**
143      * Unwraps the delegate of a possibly archive enabled file.
144      */

145     protected java.io.File JavaDoc unwrap(final java.io.File JavaDoc file) {
146         if (file instanceof File)
147             return ((File) file).getDelegate();
148         else
149             return file;
150     }
151
152     /**
153      * Creates a ZIP enabled file where necessary only,
154      * otherwise the blueprint is simply returned.
155      */

156     public java.io.File JavaDoc createFileObject(final java.io.File JavaDoc file) {
157         if (file == null)
158             return null;
159         final File wFile = wrap(file);
160         return wFile.isArchive() || wFile.isEntry()
161                 ? wFile
162                 : unwrap(file);
163     }
164
165     //
166
// Overridden methods:
167
//
168

169     public boolean isRoot(java.io.File JavaDoc file) {
170         return super.isRoot(unwrap(file));
171     }
172
173     public Boolean JavaDoc isTraversable(java.io.File JavaDoc file) {
174         final File wFile = wrap(file);
175         final Boolean JavaDoc traversable = FileView.traversable(wFile);
176         if (traversable != null)
177             return traversable;
178         return super.isTraversable(unwrap(file));
179     }
180
181     public String JavaDoc getSystemDisplayName(java.io.File JavaDoc file) {
182         final File wFile = wrap(file);
183         if (wFile.isArchive() || wFile.isEntry())
184             return wFile.getName();
185         return super.getSystemDisplayName(unwrap(file));
186     }
187
188     public String JavaDoc getSystemTypeDescription(java.io.File JavaDoc file) {
189         final File wFile = wrap(file);
190         final String JavaDoc typeDescription = FileView.typeDescription(wFile);
191         if (typeDescription != null)
192             return typeDescription;
193         return super.getSystemTypeDescription(unwrap(file));
194     }
195
196     public Icon getSystemIcon(java.io.File JavaDoc file) {
197         final File wFile = wrap(file);
198         final Icon icon = FileView.closedIcon(wFile);
199         if (icon != null)
200             return icon;
201         return super.getSystemIcon(unwrap(file));
202     }
203
204     public boolean isParent(java.io.File JavaDoc folder, java.io.File JavaDoc file) {
205         return super.isParent(wrap(folder), wrap(file))
206             || super.isParent(unwrap(folder), unwrap(file));
207     }
208
209     public java.io.File JavaDoc getChild(java.io.File JavaDoc parent, String JavaDoc child) {
210         final File wParent = wrap(parent);
211         if (wParent.isArchive() || wParent.isEntry())
212             return createFileObject(super.getChild(wParent, child));
213         return createFileObject(super.getChild(unwrap(parent), child));
214     }
215
216     public boolean isFileSystem(java.io.File JavaDoc file) {
217         return super.isFileSystem(unwrap(file));
218     }
219
220     public java.io.File JavaDoc createNewFolder(final java.io.File JavaDoc parent)
221     throws IOException {
222         final File wParent = wrap(parent);
223         if (wParent.isArchive() || wParent.isEntry()) {
224             File folder = getArchiveDetector().createFile(
225                     wParent,
226                     UIManager.getString(File.separatorChar == '\\'
227                             ? "FileChooser.win32.newFolder"
228                             : "FileChooser.other.newFolder"));
229
230             for (int i = 2; !folder.mkdirs(); i++) {
231                 if (i > 100)
232                     throw new IOException(wParent + ": Could not create new directory entry!");
233                 folder = getArchiveDetector().createFile(
234                         wParent,
235                         MessageFormat.format(
236                             UIManager.getString(File.separatorChar == '\\'
237                                 ? "FileChooser.win32.newFolder.subsequent"
238                                 : "FileChooser.other.newFolder.subsequent"),
239                             new Object JavaDoc[] { new Integer JavaDoc(i) }));
240             }
241             
242             return folder;
243         }
244         return createFileObject(super.createNewFolder(unwrap(parent)));
245     }
246
247     public boolean isHiddenFile(java.io.File JavaDoc file) {
248         return super.isHiddenFile(unwrap(file));
249     }
250
251     public boolean isFileSystemRoot(java.io.File JavaDoc file) {
252         return super.isFileSystemRoot(unwrap(file));
253     }
254
255     public boolean isDrive(java.io.File JavaDoc file) {
256         return super.isDrive(unwrap(file));
257     }
258
259     public boolean isFloppyDrive(java.io.File JavaDoc file) {
260         return super.isFloppyDrive(unwrap(file));
261     }
262
263     public boolean isComputerNode(java.io.File JavaDoc file) {
264         return super.isComputerNode(unwrap(file));
265     }
266
267     /**
268      * Creates a ZIP enabled file where necessary only,
269      * otherwise the file system view delegate is used to create the file.
270      */

271     public java.io.File JavaDoc createFileObject(java.io.File JavaDoc dir, String JavaDoc str) {
272         return createFileObject(super.createFileObject(dir, str));
273     }
274     
275     /**
276      * Creates a ZIP enabled file where necessary only,
277      * otherwise the file system view delegate is used to create the file.
278      */

279     public java.io.File JavaDoc createFileObject(String JavaDoc str) {
280         return createFileObject(super.createFileObject(str));
281     }
282
283     public java.io.File JavaDoc[] getFiles(
284             final java.io.File JavaDoc dir,
285             final boolean useFileHiding) {
286         final File smartDir = wrap(dir);
287         if (smartDir.isArchive() || smartDir.isEntry()) {
288             // dir is a ZIP file or an entry in a ZIP file.
289
return smartDir.listFiles(new FileFilter() {
290                 public boolean accept(java.io.File JavaDoc file) {
291                     return !useFileHiding || !isHiddenFile(file);
292                 }
293             });
294         } else {
295             final java.io.File JavaDoc files[] = super.getFiles(unwrap(dir), useFileHiding);
296             for (int i = files.length; --i >= 0; )
297                 files[i] = createFileObject(files[i]);
298
299             return files;
300         }
301     }
302
303     public java.io.File JavaDoc getParentDirectory(java.io.File JavaDoc file) {
304         final File wFile = wrap(file);
305         if (wFile.isEntry())
306             return createFileObject(wFile.getParentFile());
307         return createFileObject(super.getParentDirectory(unwrap(file)));
308     }
309
310     /*protected java.io.File createFileSystemRoot(java.io.File file) {
311         // As an exception to the rule, we will not delegate this call as this
312         // method has protected access.
313         // Instead, we will delegate it to our superclass and wrap a file
314         // object around it.
315         return super.createFileSystemRoot(unwrapFile(file));
316     }*/

317 }
318
Popular Tags