001/*
002  A clean reimplementation of Ptolemy II's original ExtensionFilenameFilter.
003
004  Copyright (c) 2016 The Regents of the University of California.
005  All rights reserved.
006  Permission is hereby granted, without written agreement and without
007  license or royalty fees, to use, copy, modify, and distribute this
008  software and its documentation for any purpose, provided that the above
009  copyright notice and the following two paragraphs appear in all copies
010  of this software.
011
012  IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
013  FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014  ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015  THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016  SUCH DAMAGE.
017
018  THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021  PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022  CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023  ENHANCEMENTS, OR MODIFICATIONS.
024
025  PT_COPYRIGHT_VERSION_2
026  COPYRIGHTENDKEY
027*/
028package ptolemy.gui;
029
030import java.io.File;
031import java.util.HashSet;
032import java.util.List;
033import java.util.Locale;
034import java.util.Set;
035
036/**
037 * An implementation of both javax.swing.filechooser.FileFilter and
038 * java.io.FilenameFilter that only accepts files that have one of the
039 * registered extensions.
040 * <p>
041 * This class is provided in Ptolemy II to support usage with both
042 * java.awt.FileDialog and javax.swing.JFileChooser. As it appears that on
043 * MacOSX the FileDialog implementation is better than the JFileChooser, Ptolemy
044 * II has some logic in ptolemy.gui.PtGUIUtilities.useFileDialog() to decide
045 * which "file-picker"-component to use. Several Ptolemy II classes use this
046 * utility while still passing a common filter instance to the selected
047 * component. (e.g. ptolemy.gui.Query, ptolemy.gui.Top ...)
048 * </p>
049 * <p>
050 * The javax.swing.filechooser.FileNameExtensionFilter in the JDK can only be
051 * used with JFileChooser.
052 * </p>
053 *
054 * @version $Id$
055 * @author Erwin De Ley
056 * @since Ptolemy II 11.0
057 */
058public class ExtensionFilenameFilter extends PtFilenameFilter {
059
060    /**
061     * Construct a file filter that filters out all files that do not
062     * have one of the extensions in the given list.
063     *
064     * @param extensions the file extensions to use
065     */
066    public ExtensionFilenameFilter(List<String> extensions) {
067        for (String ext : extensions) {
068            registerExtension(ext);
069        }
070    }
071
072    /**
073     * Construct a file filter that filters out all files that do not
074     * have one of the extensions in the given list.
075     *
076     * @param extensions the file extensions to use
077     */
078    public ExtensionFilenameFilter(String[] extensions) {
079        // This method is used by Kepler in gui/src/org/kepler/gui/kar/OpenArchiveAction.java
080        // See https://kepler-project.org/developers.  To build: "ant change-to -Dsuite=nightly; ant compile"
081        this(extensions, null);
082    }
083
084    /**
085     * Creates a filter that accepts the given file type, specified by
086     * a number of extensions and a meaningful description of the file
087     * types involved.
088     *
089     * @param description a description of the types of files with one
090     * of the given extensions.
091     * @param extensions the file extensions to use
092     */
093    public ExtensionFilenameFilter(String description, String... extensions) {
094        for (String ext : extensions) {
095            registerExtension(ext);
096        }
097        setDescription(description);
098    }
099
100    /**
101     * Creates a filter that accepts the given file type, specified by
102     * a number of extensions and a meaningful description of the file
103     * types involved.
104     *
105     * @param extensions the file extensions to use
106     * @param description a description of the types of files with one
107     * of the given extensions
108     */
109    public ExtensionFilenameFilter(String[] extensions, String description) {
110        // This method is used by Kepler in reporting/src/org/kepler/reporting/gui/ReportDesignerPanel.java
111        // See https://kepler-project.org/developers.  To build: "ant change-to -Dsuite=nightly; ant compile"
112        for (int i = 0; i < extensions.length; i++) {
113            registerExtension(extensions[i]);
114        }
115        if (description != null) {
116            setDescription(description);
117        }
118    }
119
120    /**
121     * Return true if the given file has one of the registered
122     * extensions, or is a directory. Otherwise, or if the file is
123     * null, return false.
124     *
125     * <p>Files whose name begins with "." are not accepted.</p>
126     *
127     * @param file The file to be checked.
128     * @return true if the given file has one of the registered
129     * extensions, or is a directory.
130     */
131    @Override
132    public boolean accept(File file) {
133        if (file == null) {
134            return false;
135        } else if (file.isDirectory()) {
136            return true;
137        } else {
138            String ext = _getExtension(file);
139            return (ext != null && _registeredExtensions.contains(ext));
140        }
141    }
142
143    /**
144     * Return true if the given file name has one of the registered
145     * extensions, or is a directory. Otherwise, or if the directory
146     * or name is null, return false.
147     *
148     * <p>Files whose name begins with "." are not accepted.</p>
149     *
150     * @param directory the parent directory of the file
151     * @param name the name of the file.
152     * @return true if the given file has one of the registered
153     * extensions, or is a directory.
154     */
155    @Override
156    public boolean accept(File directory, String name) {
157        if (name == null || directory == null) {
158            return false;
159        } else {
160            return accept(new File(directory, name));
161        }
162    }
163
164    /**
165     * @return The human readable description of the types of files
166     * accepted by this filter.
167     * @see #setDescription(String)
168     */
169    @Override
170    public String getDescription() {
171        return _description;
172    }
173
174    /**
175     * Set the human readable description of the types of files accepted by this
176     * filter.
177     *
178     * @param description the human readable description of the types
179     * of files accepted by this filter.
180     * @see #getDescription()
181     */
182    public void setDescription(String description) {
183        _description = description;
184    }
185
186    /** Get the description and the registered extensions.
187     * @return description + registered extensions
188     */
189    @Override
190    public String toString() {
191        return getDescription() + " : " + _registeredExtensions;
192    }
193
194    ///////////////////////////////////////////////////////////////////
195    ////                         protected methods                 ////
196    /**
197     * Register an additional extension to accept.
198     *
199     * @param extension
200     *            The extension to be added.
201     */
202    protected void registerExtension(String extension) {
203        if (extension == null || "".equals(extension.trim())) {
204            return;
205        } else {
206            _registeredExtensions
207                    .add(extension.trim().toLowerCase(Locale.getDefault()));
208        }
209    }
210
211    ///////////////////////////////////////////////////////////////////
212    ////                         private methods                   ////
213    /**
214     * Return the extension of the given file.
215     * <p>
216     * If the file is null, if it's name does not contain a '.', or if it ends
217     * in a '.', this method returns null.
218     * </p>
219     *
220     * @param file The file
221     * @return the extension of the file or null if the file is null,
222     * or if it has no extension.
223     */
224    private String _getExtension(File file) {
225        if (file == null) {
226            return null;
227        } else {
228            String fileName = file.getName();
229            int i = fileName.lastIndexOf('.');
230            if (i > 0 && i < fileName.length() - 1) {
231                String ext = fileName.substring(i + 1);
232                return ext.toLowerCase(Locale.getDefault());
233            } else {
234                return null;
235            }
236        }
237    }
238
239    ///////////////////////////////////////////////////////////////////
240    ////               private fields                              ////
241    private Set<String> _registeredExtensions = new HashSet<String>();
242
243    private String _description = null;
244}