View Javadoc

1   /*
2    * Copyright 2006-2016 The JGUIraffe Team.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License")
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.jguiraffe.examples.tutorial.viewset;
17  
18  import java.io.File;
19  import java.io.FileFilter;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.ObjectInputStream;
24  import java.io.ObjectOutputStream;
25  import java.io.Serializable;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collection;
29  import java.util.Comparator;
30  import java.util.Date;
31  import java.util.HashSet;
32  import java.util.List;
33  import java.util.Locale;
34  import java.util.Set;
35  
36  import net.sf.jguiraffe.examples.tutorial.model.FileData;
37  import net.sf.jguiraffe.gui.builder.components.Color;
38  import net.sf.jguiraffe.gui.builder.components.ColorHelper;
39  
40  import org.apache.commons.logging.Log;
41  import org.apache.commons.logging.LogFactory;
42  
43  /**
44   * <p>
45   * A data class for storing a view definition.
46   * </p>
47   * <p>
48   * The tutorial application allows creating a view definition for each
49   * directory. A view definition stores several properties which define how a
50   * specific directory is displayed, e.g. colors, sort order, filter conditions,
51   * etc. This class stores all the data of a view definition. An instance is used
52   * by the view settings dialog as model bean.
53   * </p>
54   *
55   * @author Oliver Heger
56   * @version $Id: ViewSettings.java 205 2012-01-29 18:29:57Z oheger $
57   */
58  public class ViewSettings implements Serializable
59  {
60      /** Constant for the name of the file with the view settings. */
61      public static final String VIEW_SETTINGS_FILE = ".viewsettings";
62  
63      /**
64       * Constant for the name under which this instance is stored in the context.
65       */
66      public static final String CTX_NAME = "viewSettingsModel";
67  
68      /**
69       * The serial version UID.
70       */
71      private static final long serialVersionUID = 20100111L;
72  
73      /** The logger. */
74      private static final Log LOG = LogFactory.getLog(ViewSettings.class);
75  
76      /** The background color. */
77      private Color backgroundColor;
78  
79      /** The foreground color. */
80      private Color foregroundColor;
81  
82      /** The selection background color. */
83      private Color selectionBackground;
84  
85      /** The selection foreground color. */
86      private Color selectionForeground;
87  
88      /** The index of the sort color. */
89      private Integer sortColumn;
90  
91      /** The sort mode for directories. */
92      private Integer sortDirectories;
93  
94      /** The sort descending flag. */
95      private boolean sortDescending;
96  
97      /** A flag whether the filter for file types is active. */
98      private boolean filterTypes;
99  
100     /** An array with the file types to filter for. */
101     private String[] fileTypes;
102 
103     /** A flag whether the filter for file size is active. */
104     private boolean filterSize;
105 
106     /** The minimum file size for the size filter. */
107     private Integer minFileSize;
108 
109     /** A flag whether the date filter is active. */
110     private boolean filterDate;
111 
112     /** The from date for the date filter. */
113     private Date fileDateFrom;
114 
115     /** The to date for the date filter. */
116     private Date fileDateTo;
117 
118     /**
119      * Creates a new instance of {@code ViewSettings} and initializes it with
120      * default values.
121      */
122     public ViewSettings()
123     {
124         initDefaults();
125     }
126 
127     /**
128      * Stores this object in the specified directory. Using this method the view
129      * settings for this directory can be made persistent.
130      *
131      * @param directory the target directory
132      * @throws IOException if an error occurs
133      */
134     public void save(File directory) throws IOException
135     {
136         File settingsFile = new File(directory, VIEW_SETTINGS_FILE);
137         ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream(
138                 settingsFile));
139 
140         try
141         {
142             os.writeObject(this);
143             LOG.info("Saved settings file: " + settingsFile);
144         }
145         finally
146         {
147             os.close();
148         }
149     }
150 
151     /**
152      * Returns the {@code ViewSettings} object for the specified directory. If
153      * in this directory a file with the reserved name for the {@code
154      * ViewSettings} object exists, it is loaded. If this file does not exist or
155      * if loading this file causes an error, a default instance is returned.
156      *
157      * @param directory the directory in question
158      * @return the {@code ViewSettings} object for this directory
159      */
160     public static ViewSettings forDirectory(File directory)
161     {
162         File settingsFile = new File(directory, VIEW_SETTINGS_FILE);
163 
164         if (settingsFile.exists())
165         {
166             LOG.info("Trying to load view settings from " + settingsFile);
167             ObjectInputStream is = null;
168             try
169             {
170                 is = new ObjectInputStream(new FileInputStream(settingsFile));
171                 return (ViewSettings) is.readObject();
172             }
173             catch (IOException ioex)
174             {
175                 LOG.error("Error when reading view settings!", ioex);
176             }
177             catch (ClassNotFoundException cfex)
178             {
179                 LOG.error("Class not found when reading view settings!", cfex);
180             }
181             finally
182             {
183                 if (is != null)
184                 {
185                     try
186                     {
187                         is.close();
188                     }
189                     catch (IOException ioex)
190                     {
191                         LOG.warn("Error when closing stream.", ioex);
192                     }
193                 }
194             }
195         }
196 
197         return new ViewSettings(); // return default settings
198     }
199 
200     public Color getBackgroundColor()
201     {
202         return backgroundColor;
203     }
204 
205     public void setBackgroundColor(Color backgroundColor)
206     {
207         this.backgroundColor = backgroundColor;
208     }
209 
210     public Color getForegroundColor()
211     {
212         return foregroundColor;
213     }
214 
215     public void setForegroundColor(Color foregroundColor)
216     {
217         this.foregroundColor = foregroundColor;
218     }
219 
220     public Color getSelectionBackground()
221     {
222         return selectionBackground;
223     }
224 
225     public void setSelectionBackground(Color selectionBackground)
226     {
227         this.selectionBackground = selectionBackground;
228     }
229 
230     public Color getSelectionForeground()
231     {
232         return selectionForeground;
233     }
234 
235     public void setSelectionForeground(Color selectionForeground)
236     {
237         this.selectionForeground = selectionForeground;
238     }
239 
240     public Integer getSortColumn()
241     {
242         return sortColumn;
243     }
244 
245     public void setSortColumn(Integer sortColumn)
246     {
247         this.sortColumn = sortColumn;
248     }
249 
250     public Integer getSortDirectories()
251     {
252         return sortDirectories;
253     }
254 
255     public void setSortDirectories(Integer sortDirectories)
256     {
257         this.sortDirectories = sortDirectories;
258     }
259 
260     public boolean isSortDescending()
261     {
262         return sortDescending;
263     }
264 
265     public void setSortDescending(boolean sortDescending)
266     {
267         this.sortDescending = sortDescending;
268     }
269 
270     public boolean isFilterTypes()
271     {
272         return filterTypes;
273     }
274 
275     public void setFilterTypes(boolean filterTypes)
276     {
277         this.filterTypes = filterTypes;
278     }
279 
280     public String[] getFileTypes()
281     {
282         return fileTypes;
283     }
284 
285     public void setFileTypes(String[] fileTypes)
286     {
287         this.fileTypes = fileTypes;
288     }
289 
290     public boolean isFilterSize()
291     {
292         return filterSize;
293     }
294 
295     public void setFilterSize(boolean filterSize)
296     {
297         this.filterSize = filterSize;
298     }
299 
300     public Integer getMinFileSize()
301     {
302         return minFileSize;
303     }
304 
305     public void setMinFileSize(Integer minFileSize)
306     {
307         this.minFileSize = minFileSize;
308     }
309 
310     public boolean isFilterDate()
311     {
312         return filterDate;
313     }
314 
315     public void setFilterDate(boolean filterDate)
316     {
317         this.filterDate = filterDate;
318     }
319 
320     public Date getFileDateFrom()
321     {
322         return fileDateFrom;
323     }
324 
325     public void setFileDateFrom(Date fileDateFrom)
326     {
327         this.fileDateFrom = fileDateFrom;
328     }
329 
330     public Date getFileDateTo()
331     {
332         return fileDateTo;
333     }
334 
335     public void setFileDateTo(Date fileDateTo)
336     {
337         this.fileDateTo = fileDateTo;
338     }
339 
340     /**
341      * Creates a {@code Comparator} object that implements the sort order
342      * specified in this object.
343      *
344      * @return the {@code Comparator}
345      */
346     public Comparator<FileData> createComparator()
347     {
348         int sortCol = (getSortColumn() == null) ? 0 : getSortColumn()
349                 .intValue();
350         Comparator<FileData> fileComp;
351         switch (sortCol)
352         {
353         case 2:
354             fileComp = new FileSizeComparator();
355             break;
356         case 1:
357             fileComp = new FileDateComparator();
358             break;
359         default:
360             fileComp = new FileNameComparator();
361         }
362 
363         int dirComp = (getSortDirectories() == null) ? 0 : getSortDirectories()
364                 .intValue();
365         return new FileDataComparator(new FileDirComparator(dirComp), fileComp,
366                 isSortDescending());
367     }
368 
369     /**
370      * Creates a {@code FileFilter} object that implements the filter criteria
371      * defined for this object. This filter can be used directly when listing
372      * the directory this {@code ViewSettings} object is associated with.
373      *
374      * @return a {@code FileFilter} for filtering a directory listing
375      */
376     public FileFilter createFileFilter()
377     {
378         List<FileFilter> filters = new ArrayList<FileFilter>(3);
379 
380         if (isFilterTypes())
381         {
382             filters.add(new FileTypeFilter(new HashSet<String>(Arrays
383                     .asList(fileTypes))));
384         }
385         if (isFilterDate())
386         {
387             filters.add(new FileDateFilter(fileDateFrom, fileDateTo));
388         }
389         if (isFilterSize())
390         {
391             filters.add(new FileSizeFilter(minFileSize));
392         }
393 
394         return new CombinedFileFilter(filters);
395     }
396 
397     /**
398      * Sets default values for most of the properties. This method is called
399      * when a new instance is created. It ensures that meaningful default values
400      * are set when the view settings dialog is displayed.
401      */
402     private void initDefaults()
403     {
404         setBackgroundColor(ColorHelper.NamedColor.WHITE.getColor());
405         setForegroundColor(ColorHelper.NamedColor.BLACK.getColor());
406         setSelectionBackground(ColorHelper.NamedColor.BLUE.getColor());
407         setSelectionForeground(ColorHelper.NamedColor.BLACK.getColor());
408         setSortColumn(0);
409         setSortDirectories(null);
410         setSortDescending(false);
411         setMinFileSize(1);
412     }
413 
414     /**
415      * A specialized comparator implementation that compares files by their
416      * name.
417      */
418     private static class FileNameComparator implements Comparator<FileData>
419     {
420         @Override
421         public int compare(FileData o1, FileData o2)
422         {
423             return o1.getName().compareToIgnoreCase(o2.getName());
424         }
425     }
426 
427     /**
428      * A specialized comparator implementation that compares files by their
429      * size.
430      */
431     private static class FileSizeComparator implements Comparator<FileData>
432     {
433         @Override
434         public int compare(FileData o1, FileData o2)
435         {
436             return (int) (o1.getSize() - o2.getSize());
437         }
438     }
439 
440     /**
441      * A specialized comparator implementation that compares files by their
442      * date.
443      */
444     private static class FileDateComparator implements Comparator<FileData>
445     {
446         @Override
447         public int compare(FileData o1, FileData o2)
448         {
449             return o1.getLastModified().compareTo(o2.getLastModified());
450         }
451     }
452 
453     /**
454      * A comparator for comparing files with directories. It applies the sort
455      * order for directories.
456      */
457     private static class FileDirComparator implements Comparator<FileData>
458     {
459         /** The sort order for directories. */
460         private final int directorySortOrder;
461 
462         public FileDirComparator(int dirSortOrder)
463         {
464             directorySortOrder = dirSortOrder;
465         }
466 
467         @Override
468         public int compare(FileData o1, FileData o2)
469         {
470             if (directorySortOrder == 2)
471             {
472                 // directories are sorted as files
473                 return 0;
474             }
475 
476             boolean dir1 = o1.getFile().isDirectory();
477             boolean dir2 = o2.getFile().isDirectory();
478             if (dir1 ^ dir2)
479             {
480                 // one is a file and one is a directory
481                 int result = (directorySortOrder == 0) ? -1 : 1;
482                 if (dir2)
483                 {
484                     result = -result;
485                 }
486                 return result;
487             }
488             else
489             {
490                 return 0;
491             }
492         }
493     }
494 
495     /**
496      * A specialized comparator implementation for comparing {@code FileData}
497      * objects. This implementation takes all sort criteria into account
498      * specified for the file list.
499      */
500     private static class FileDataComparator implements Comparator<FileData>
501     {
502         /** The comparator for directories and files. */
503         private final Comparator<FileData> fileDirComparator;
504 
505         /** The comparator for files. */
506         private final Comparator<FileData> fileComparator;
507 
508         /** A flag for reverse sort order. */
509         private final boolean reverseOrder;
510 
511         public FileDataComparator(Comparator<FileData> dirComp,
512                 Comparator<FileData> fileComp, boolean reverse)
513         {
514             fileDirComparator = dirComp;
515             fileComparator = fileComp;
516             reverseOrder = reverse;
517         }
518 
519         @Override
520         public int compare(FileData o1, FileData o2)
521         {
522             int c = fileDirComparator.compare(o1, o2);
523             if (c != 0)
524             {
525                 return c;
526             }
527 
528             c = fileComparator.compare(o1, o2);
529             if (reverseOrder)
530             {
531                 c = -c;
532             }
533 
534             return c;
535         }
536     }
537 
538     /**
539      * A filter implementation that deals with the file date range specified for
540      * the current {@code ViewSettings} object.
541      */
542     private static class FileDateFilter implements FileFilter
543     {
544         /** The from date. */
545         private final Date dtFrom;
546 
547         /** The to date. */
548         private final Date dtTo;
549 
550         public FileDateFilter(Date from, Date to)
551         {
552             dtFrom = from;
553             dtTo = to;
554         }
555 
556         @Override
557         public boolean accept(File file)
558         {
559             Date fileDate = new Date(file.lastModified());
560             return (dtFrom == null || dtFrom.before(fileDate) || dtFrom
561                     .equals(fileDate))
562                     && (dtTo == null || dtTo.after(fileDate));
563         }
564     }
565 
566     /**
567      * A file filter implementation that corresponds to the file size filter
568      * criterion specified for the current {@code ViewSettings} object.
569      */
570     private static class FileSizeFilter implements FileFilter
571     {
572         /** The minimum file size (in bytes). */
573         private final long minimumSize;
574 
575         /**
576          * Creates a new instance of {@code FileSizeFilter} and initializes it
577          * with the minimum file size to be accepted.
578          *
579          * @param minSize the minimum file size (in KB)
580          */
581         public FileSizeFilter(Integer minSize)
582         {
583             minimumSize = 1024L * minSize.longValue();
584         }
585 
586         @Override
587         public boolean accept(File file)
588         {
589             return file.length() >= minimumSize;
590         }
591     }
592 
593     /**
594      * A file filter implementation that corresponds to the file types criterion
595      * specified for the current {@code ViewSettings} object. This filter
596      * accepts only files whose name extension is part of a given set.
597      */
598     private static class FileTypeFilter implements FileFilter
599     {
600         /** The set with name extensions to be accepted. */
601         private final Set<String> extensions;
602 
603         /**
604          * Creates a new instance of {@code FileTypeFilter} and initializes it
605          * with the file name extensions to be accepted.
606          *
607          * @param exts the set with the allowed extensions
608          */
609         public FileTypeFilter(Set<String> exts)
610         {
611             extensions = exts;
612         }
613 
614         @Override
615         public boolean accept(File file)
616         {
617             int extpos = file.getName().lastIndexOf('.');
618             if (extpos < 0)
619             {
620                 // no extension
621                 return false;
622             }
623 
624             String ext = file.getName().substring(extpos + 1).toLowerCase(
625                     Locale.ENGLISH);
626             return extensions.contains(ext);
627         }
628     }
629 
630     /**
631      * A file filter implementation that combines multiple other filter objects.
632      * An instance of this class is used to realize the filter conditions
633      * defined for a {@code ViewSettings} object. For each filter criterion
634      * specified by the user a sub filter is added to the combined filter.
635      */
636     private static class CombinedFileFilter implements FileFilter
637     {
638         /** A collection with the sub filters. */
639         private final Collection<FileFilter> subFilters;
640 
641         /**
642          * Creates a new instance of {@code CombinedFileFilter} and sets the
643          * collection with the sub filters.
644          *
645          * @param subs the sub filters
646          */
647         public CombinedFileFilter(Collection<FileFilter> subs)
648         {
649             subFilters = subs;
650         }
651 
652         @Override
653         public boolean accept(File file)
654         {
655             for (FileFilter filter : subFilters)
656             {
657                 if (!filter.accept(file))
658                 {
659                     return false;
660                 }
661             }
662 
663             return true;
664         }
665     }
666 }