001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: FilesystemDataSource.java,v $
023   Revision 1.7  2004/05/31 07:30:26  markl
024   Final cleanup and bugfixes of kiwi.ui.model.
025
026   Revision 1.6  2004/03/23 06:50:13  markl
027   I18N, modified to use KTreeTable, added support for multiple roots
028
029   Revision 1.5  2003/01/19 09:33:06  markl
030   Javadoc & comment header updates.
031
032   Revision 1.4  2001/03/12 04:11:42  markl
033   Source code cleanup.
034
035   Revision 1.3  1999/07/05 08:07:04  markl
036   Bug fix.
037
038   Revision 1.2  1999/01/10 03:12:19  markl
039   added GPL header & RCS tag
040   ----------------------------------------------------------------------------
041*/
042
043package kiwi.ui.model;
044
045import java.awt.Image;
046import java.io.File;
047import java.text.SimpleDateFormat;
048import java.util.*;
049import javax.swing.Icon;
050
051import kiwi.util.*;
052
053/** This class is an implementation of <code>HierarchicalDataSource</code>
054  * wherein tree nodes represent files in the local filesystem. The
055  * <code>ignoreFiles</code> argument of some forms of the constructor allows
056  * for the creation of directory-only data sources. These are useful for
057  * driving a directory chooser, for example.
058  *
059  * @see java.io.File
060  *
061  * @author Mark Lindner
062  */
063
064public class FilesystemDataSource implements TreeDataSource
065  {
066  private FileRoot root;
067  private Date date = new Date();
068  private static final Icon FOLDER_OPEN_ICON = KiwiUtils.getResourceManager()
069    .getIcon("folder-open.gif");
070  private static final Icon FOLDER_CLOSED_ICON = KiwiUtils.getResourceManager()
071    .getIcon("folder-closed.gif");
072  private static final Icon FOLDER_LOCKED_ICON = KiwiUtils.getResourceManager()
073    .getIcon("folder-locked.gif");
074  private static final Icon DOCUMENT_ICON = KiwiUtils.getResourceManager()
075    .getIcon("document.gif");
076  private static final Icon COMPUTER_ICON = KiwiUtils.getResourceManager()
077    .getIcon("computer.gif");
078  private boolean ignoreFiles = false;
079  private static final String columns[];
080  private LocaleManager lm;
081  private static final String[] emptyList = new String[0];
082  private static final String FILE_COLUMN, SIZE_COLUMN, DATE_COLUMN,
083    TIME_COLUMN;
084  private static final Class types[] = new Class[] { String.class,
085                                                     String.class,
086                                                     String.class,
087                                                     String.class };
088  private static final String ALL_FILESYSTEMS;
089
090  /*
091   */
092  
093  static
094    {
095    LocaleManager lm = LocaleManager.getDefault();
096    LocaleData loc = lm.getLocaleData("KiwiMisc");
097
098    FILE_COLUMN = loc.getMessage("kiwi.column.file");
099    SIZE_COLUMN = loc.getMessage("kiwi.column.size");
100    DATE_COLUMN = loc.getMessage("kiwi.column.date");
101    TIME_COLUMN = loc.getMessage("kiwi.column.time");
102    ALL_FILESYSTEMS = loc.getMessage("kiwi.label.all_filesystems");
103
104    columns = new String[] { FILE_COLUMN, SIZE_COLUMN, DATE_COLUMN,
105                             TIME_COLUMN };
106      
107    }
108  
109  /** Construct a new <code>FilesystemDataSource</code> with roots
110   * for all available filesystems.
111   *
112   * @since Kiwi 2.0
113   */
114  
115  public FilesystemDataSource()
116    {
117    _init(new FileRoot(), false);
118    }
119  
120  /** Construct a new <code>FilesystemDataSource</code> wiht the given roots.
121    *
122    * @param roots The filesystem roots for this datasource.
123    * @since Kiwi 2.0
124    */
125
126  public FilesystemDataSource(File roots[])
127    {
128    _init(new FileRoot(roots), false);
129    }
130
131  /** Construct a new <code>FilesystemDataSource</code> with roots
132   * for all available filesystems.
133   *
134   * @param ignoreFiles A flag specifying whether ordinary files
135   * (non-directories) should be ignored or displayed.
136   */
137
138  public FilesystemDataSource(boolean ignoreFiles)
139    {
140    _init(new FileRoot(), ignoreFiles);
141    }
142
143  /** Construct a new <code>FilesystemDataSource</code>.
144    *
145    * @param root The root directory.
146    * @param ignoreFiles A flag specifying whether ordinary files
147    * (non-directories) should be ignored or displayed.
148    *
149    * @exception java.lang.IllegalArgumentException if <code>root</code> is not
150    * a directory.
151    */
152
153  public FilesystemDataSource(File root, boolean ignoreFiles)
154    {
155    if(root != null && !root.isDirectory())
156      throw(new IllegalArgumentException("Root must be a directory!"));
157
158    _init(new FileRoot(root), ignoreFiles);
159    }
160
161  /** Construct a new <code>FilesystemDataSource</code>.
162    *
163    * @param roots The root directories.
164    * @param ignoreFiles A flag specifying whether ordinary files
165    * (non-directories) should be ignored or displayed.
166    *
167    * @exception java.lang.IllegalArgumentException if <code>root</code> is not
168    * a directory.
169    *
170    * @since Kiwi 2.0
171    */
172
173  public FilesystemDataSource(File roots[], boolean ignoreFiles)
174    {
175    for(int i = 0; i < roots.length; i++)
176      if(!roots[i].isDirectory())
177        throw(new IllegalArgumentException("Roots must be directories!"));
178
179    _init(new FileRoot(roots), ignoreFiles);
180    }
181  
182  /*
183   */
184  
185  private void _init(FileRoot root, boolean ignoreFiles)
186    {
187    this.ignoreFiles = ignoreFiles;
188    this.root = root;
189
190    lm = LocaleManager.getDefault();
191    }
192
193  /** Get the root object.
194   *
195   * @return The <code>FileRoot</code> "virtual root" object which is
196   * the parent of the root files with which this data source was
197   * created.
198   */
199
200  public Object getRoot()
201    {
202    return(root);
203    }
204
205  /** Get the children of a given node. */
206
207  public Object[] getChildren(Object node)
208    {
209    System.out.println("In FilesystemDataSource.getChildren()");
210    
211    if(node.getClass() == FileRoot.class)
212      return(((FileRoot)node).getRoots());
213      
214    File f = (File)node;
215    String[] children = emptyList;
216
217    try { children = f.list(); } catch(Exception e) { }
218
219    Arrays.sort(children);
220    
221    return(makeNodes(f, children));
222    }
223
224  /* create an array of Files from an array of filenames */
225
226  private File[] makeNodes(File parent, String[] list)
227    {
228    File f;
229    Vector v = new Vector();
230
231    for(int i = 0; i < list.length; i++)
232      {
233      if(parent == null)
234        f = new File(list[i]);
235      else
236        f = new File(parent, list[i]);
237
238      if(ignoreFiles && !f.isDirectory())
239        continue;
240      v.addElement(f);
241      }
242
243    File nodes[] = new File[v.size()];
244    v.copyInto(nodes);
245    return(nodes);
246    }
247
248  /*
249   */
250
251  public String getLabel(Object node)
252    {
253    if(node.getClass() == FileRoot.class)
254      return(ALL_FILESYSTEMS);
255
256    File f = (File)node;
257    if(root.isRoot(f))
258      return(f.getPath());
259    else
260      return(f.getName());
261    }
262
263  /*
264   */
265
266  public Icon getIcon(Object node, boolean isExpanded)
267    {
268    if(node.getClass() == FileRoot.class)
269      return(COMPUTER_ICON);
270
271    File f = (File)node;
272
273    if(f.isDirectory())
274      {
275      if(! f.canRead())
276        return(FOLDER_LOCKED_ICON);
277
278      return(isExpanded ? FOLDER_OPEN_ICON : FOLDER_CLOSED_ICON);
279      }
280    else
281      return(DOCUMENT_ICON);
282    }
283
284  /*
285   */
286  
287  public boolean isExpandable(Object node)
288    {
289    if(node.getClass() == FileRoot.class)
290      return(true);
291
292    File f = (File)node;
293
294    return(f.isDirectory() && f.canRead());
295    }
296
297  /** Get the value for a given property. */
298
299  public Object getValueForProperty(Object node, String property)
300    {
301    if(node == null)
302      {
303      if(property.equals(COLUMN_NAMES_PROPERTY))
304        return(columns);
305      else if(property.equals(COLUMN_TYPES_PROPERTY))
306        return(types);
307      else
308        return(null);
309      }
310
311    if(! (node instanceof File))
312      return(null);
313
314    File f = (File)node;
315
316    if(property.equals(FILE_COLUMN))
317      return(f);
318    
319    else if(property.equals(SIZE_COLUMN))
320      {
321      long len = f.length();
322      
323      len = (len + 1023) / 1024;
324      if(len < 1024)
325        return(lm.formatInteger(len, true) + " Kb");
326
327      len = (len + 1023) / 1024;
328      return(lm.formatInteger(len, true) + " Mb");
329      }
330    
331    else if(property.equals(DATE_COLUMN))
332      {
333      date.setTime(f.lastModified());
334      return(lm.formatDate(date, lm.MEDIUM));
335      }
336    
337    else if(property.equals(TIME_COLUMN))
338      {
339      date.setTime(f.lastModified());
340      return(lm.formatTime(date, lm.SHORT));
341      }
342    
343    else
344      return(null);
345    }
346
347  /** A virtual filesystem root. This object encapsulates the
348   * collection of filesystem roots. (Some platforms, namely Windows, have
349   * more than one root directory in the filesystem.)
350   */
351
352  public final class FileRoot
353    {
354    File roots[];
355    
356    FileRoot()
357      {
358      roots = File.listRoots();
359      }
360
361    FileRoot(File roots[])
362      {
363      this.roots = roots;
364      }
365
366    FileRoot(File root)
367      {
368      if(root != null)
369        {
370        roots = new File[1];
371        roots[0] = root;
372        }
373      else
374        roots = File.listRoots();
375      }
376
377    public boolean isRoot(File file)
378      {
379      for(int i = 0; i < roots.length; i++)
380        {
381        if(roots[i] == file)
382          return(true);
383        }
384
385      return(false);
386      }
387
388    /** Get the list of roots. */
389    
390    public File[] getRoots()
391      {
392      return(roots);
393      }
394
395    /** Get the string representation of this object.
396     *
397     * @return The empty string.
398     */
399    
400    public String toString()
401      {
402      return("");
403      }
404    }
405  
406  }
407
408/* end of source file */