001    /* FileSystemView.java --
002       Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.swing.filechooser;
039    
040    import java.io.File;
041    import java.io.IOException;
042    import java.util.ArrayList;
043    
044    import javax.swing.Icon;
045    import javax.swing.JFileChooser;
046    
047    
048    /**
049     * The base class providing a view of the file system for use by the
050     * {@link JFileChooser} component.
051     */
052    public abstract class FileSystemView
053    {
054      /** The instance returned by {@link #getFileSystemView()}. */
055      private static FileSystemView defaultFileSystemView;
056    
057      /**
058       * Creates a new file object with the given name in the specified directory.
059       *
060       * @param dir  the directory (<code>null</code> permitted).
061       * @param filename  the file name.
062       *
063       * @return A new file object.
064       */
065      public File createFileObject(File dir, String filename)
066      {
067        return new File(dir, filename);
068      }
069    
070      /**
071       * Creates a new file object from the specified path.
072       *
073       * @param path  the path.
074       *
075       * @return A new file object.
076       */
077      public File createFileObject(String path)
078      {
079        File f = new File(path);
080        if (isFileSystemRoot(f))
081          f = this.createFileSystemRoot(f);
082        return f;
083      }
084    
085      /**
086       * DOCUMENT ME!
087       *
088       * @param f DOCUMENT ME!
089       *
090       * @return DOCUMENT ME!
091       */
092      protected File createFileSystemRoot(File f)
093      {
094        File[] roots = File.listRoots();
095        if (roots == null)
096          return null;
097        return roots[0];
098      }
099    
100      /**
101       * Creates a new folder with a unique name in the specified directory and
102       * returns a {@link File} object representing the new directory.
103       *
104       * @param containingDir  the directory to contain the new folder
105       *                       (<code>null</code> not permitted).
106       *
107       * @return A {@link File} object representing the new directory.
108       *
109       * @throws IOException if an exception occurs while creating the new
110       *                     directory.
111       */
112      public abstract File createNewFolder(File containingDir)
113                                    throws IOException;
114    
115      /**
116       * DOCUMENT ME!
117       *
118       * @param parent DOCUMENT ME!
119       * @param fileName DOCUMENT ME!
120       *
121       * @return DOCUMENT ME!
122       */
123      public File getChild(File parent, String fileName)
124      {
125        // FIXME: Handle the case when parent and child are special folders.
126        return new File(parent, fileName);
127      }
128    
129      /**
130       * Returns the default directory.
131       *
132       * @return The default directory.
133       */
134      public File getDefaultDirectory()
135      {
136        return getHomeDirectory();
137      }
138    
139      /**
140       * Returns an array containing the files in the given directory.  The
141       * <code>useFileHiding</code> controls whether or not hidden files are
142       * included in the result.
143       *
144       * @param dir  the directory (if <code>null</code>
145       * @param useFileHiding  a flag that controls whether or not hidden files are
146       *                       included in the result (pass in <code>true</code> to
147       *                       exclude hidden files).
148       *
149       * @return The files in the given directory (possibly <code>null</code>).
150       */
151      public File[] getFiles(File dir, boolean useFileHiding)
152      {
153        if (dir == null || dir.listFiles() == null)
154          return null;
155        File[] files = dir.listFiles();
156        if (! useFileHiding)
157          return files;
158        ArrayList trim = new ArrayList();
159        for (int i = 0; i < files.length; i++)
160          if (! files[i].isHidden())
161            trim.add(files[i]);
162        File[] value = (File[]) trim.toArray(new File[trim.size()]);
163        return value;
164      }
165    
166      /**
167       * Returns a default {@link FileSystemView} appropriate for the platform.
168       *
169       * @return A default {@link FileSystemView} appropriate for the platform.
170       */
171      public static FileSystemView getFileSystemView()
172      {
173        if (defaultFileSystemView == null)
174          {
175            // FIXME: We need to support other file systems too.
176            defaultFileSystemView = new UnixFileSystemView();
177          }
178        return defaultFileSystemView;
179      }
180    
181      /**
182       * Returns the home directory for the current user.
183       *
184       * @return The home directory for the current user.
185       */
186      public File getHomeDirectory()
187      {
188        return createFileObject(System.getProperty("user.home"));
189      }
190    
191      /**
192       * Returns the parent directory for the given file/directory.
193       *
194       * @param f  the file/directory.
195       *
196       * @return The parent directory (or <code>null</code> if there is no parent
197       *         directory).
198       */
199      public File getParentDirectory(File f)
200      {
201        if (f == null)
202          return null;
203        return f.getParentFile();
204      }
205    
206      /**
207       * Returns an array containing the file system roots.  On Unix-like platforms,
208       * this array will contain just a single item ("/"), while other platforms
209       * may return multiple roots.
210       * <p>
211       * This method is implemented to return <code>null</code>, subclasses must
212       * override this method.
213       *
214       * @return An array containing the file system roots.
215       */
216      public File[] getRoots()
217      {
218        // subclass
219        return null;
220      }
221    
222      /**
223       * Returns the name of a file as it would be displayed by the underlying
224       * system.
225       *
226       * @param f  the file.
227       *
228       * @return the name of a file as it would be displayed by the underlying
229       *         system
230       *
231       * @specnote The specification suggests that the information here is
232       *           fetched from a ShellFolder class. This seems to be a non public
233       *           private file handling class. We simply return File.getName()
234       *           here and leave special handling to subclasses.
235       */
236      public String getSystemDisplayName(File f)
237      {
238        String name = null;
239        if (f != null)
240          name = f.getName();
241        return name;
242      }
243    
244      /**
245       * Returns the icon that would be displayed for the given file by the
246       * underlying system.  This implementation returns <code>null</code>,
247       * subclasses must override.
248       *
249       * @param f  the file.
250       *
251       * @return <code>null</code>.
252       */
253      public Icon getSystemIcon(File f)
254      {
255        return null;
256      }
257    
258      /**
259       * Returns the type description of a file that would be displayed by the
260       * underlying system.  This implementation returns <code>null</code>,
261       * subclasses must override.
262       *
263       * @param f  the file.
264       *
265       * @return <code>null</code>.
266       */
267      public String getSystemTypeDescription(File f)
268      {
269        return null;
270      }
271    
272      /**
273       * DOCUMENT ME!
274       *
275       * @param dir DOCUMENT ME!
276       *
277       * @return DOCUMENT ME!
278       */
279      public boolean isComputerNode(File dir)
280      {
281        return false;
282      }
283    
284      /**
285       * Returns <code>true</code> if the given directory represents a disk
286       * drive, and <code>false</code> otherwise.  This default implementation
287       * always returns <code>false</code>.
288       *
289       * @param dir  the directory.
290       *
291       * @return <code>false</code>.
292       */
293      public boolean isDrive(File dir)
294      {
295        return false;
296      }
297    
298      /**
299       * Returns <code>true</code> if <code>f</code> is a file or directory, and
300       * <code>false</code> otherwise.
301       *
302       * @param f  the file/directory.
303       *
304       * @return <code>true</code> if <code>f</code> is a file or directory, and
305       * <code>false</code> otherwise.
306       */
307      public boolean isFileSystem(File f)
308      {
309        return (f.isFile() || f.isDirectory());
310      }
311    
312      /**
313       * Returns <code>true</code> if the given directory is a file system root,
314       * and <code>false</code> otherwise.
315       *
316       * @param dir  the directory.
317       *
318       * @return <code>true</code> if the given directory is a file system root,
319       *          and <code>false</code> otherwise.
320       */
321      public boolean isFileSystemRoot(File dir)
322      {
323        File[] roots = File.listRoots();
324        if (roots == null || dir == null)
325          return false;
326        String filename = dir.getAbsolutePath();
327        for (int i = 0; i < roots.length; i++)
328          if (roots[i].getAbsolutePath().equals(filename))
329            return true;
330        return false;
331      }
332    
333      /**
334       * Returns <code>true</code> if the given directory represents a floppy
335       * drive, and <code>false</code> otherwise.  This default implementation
336       * always returns <code>false</code>.
337       *
338       * @param dir  the directory.
339       *
340       * @return <code>false</code>.
341       */
342      public boolean isFloppyDrive(File dir)
343      {
344        return false;
345      }
346    
347      /**
348       * Returns <code>true</code> if the given file is hidden, and
349       * <code>false</code> otherwise.
350       *
351       * @param f  the file.
352       *
353       * @return <code>true</code> if the given file is hidden, and
354       *         <code>false</code> otherwise.
355       */
356      public boolean isHiddenFile(File f)
357      {
358        return f.isHidden();
359      }
360    
361      /**
362       * Returns <code>true</code> if <code>folder</code> is the parent of
363       * <code>file</code>, and <code>false</code> otherwise.
364       *
365       * @param folder  the folder (<code>null</code> not permitted).
366       * @param file  the file (<code>null</code> not permitted).
367       *
368       * @return <code>true</code> if <code>folder</code> is the parent of
369       *         <code>file</code>, and <code>false</code> otherwise.
370       */
371      public boolean isParent(File folder, File file)
372      {
373        File parent = file.getParentFile();
374        if (parent == null)
375          return false;
376        return folder.equals(parent);
377      }
378    
379      /**
380       * DOCUMENT ME!
381       *
382       * @param f DOCUMENT ME!
383       *
384       * @return DOCUMENT ME!
385       */
386      public boolean isRoot(File f)
387      {
388        // These are not file system roots.
389        return false;
390      }
391    
392      /**
393       * Returns <code>true</code> if the file is traversable, and
394       * <code>false</code> otherwise.  Here, all directories are considered
395       * traversable, and files are considered non-traversable.
396       *
397       * @param f  the file or directory (<code>null</code> not permitted).
398       *
399       * @return <code>true</code> if the file is traversable, and
400       *         <code>false</code> otherwise.
401       */
402      public Boolean isTraversable(File f)
403      {
404        // Tested. A directory where the user has no permission to rwx is still
405        // traversable. (No files are listed when you traverse the directory)
406        // My best guess is that as long as it's a directory, the file is
407        // traversable.
408        return Boolean.valueOf(f.isDirectory());
409      }
410    }