001/*
002 * Copyright (c) 2005 Einar Pehrson <einar@pehrson.nu>.
003 *
004 * This file is part of
005 * CleanSheets - a spreadsheet application for the Java platform.
006 *
007 * CleanSheets is free software; you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License as published by
009 * the Free Software Foundation; either version 2 of the License, or
010 * (at your option) any later version.
011 *
012 * CleanSheets is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015 * GNU General Public License for more details.
016 *
017 * You should have received a copy of the GNU General Public License
018 * along with CleanSheets; if not, write to the Free Software
019 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
020 */
021package csheets.ui;
022
023import java.awt.Component;
024import java.io.File;
025import java.io.FilenameFilter;
026import java.util.ArrayList;
027import java.util.List;
028import java.util.Properties;
029
030import javax.swing.JFileChooser;
031import javax.swing.filechooser.FileFilter;
032
033import csheets.SpreadsheetAppEvent;
034import csheets.SpreadsheetAppListener;
035import csheets.io.FilenameExtensionFilter;
036
037/**
038 * A file chooser that loads choosable file types from properties.
039 * @author Einar Pehrson
040 */
041@SuppressWarnings("serial")
042public class FileChooser extends JFileChooser implements SpreadsheetAppListener {
043
044        /** The parent component of dialogs created by the chooser */
045        private Component parent;
046
047        /** The file filters used by the chooser */
048        private List<Filter> filters = new ArrayList<Filter>();
049
050        /**
051         * Creates a new file chooser. Choosable file types are loaded from the
052         * given properties. 
053         * Dialogs are shown with the given component as parent.
054         * @param parent the parent component of dialogs
055         * @param props the user properties
056         */
057        public FileChooser(Component parent, Properties props) {
058                // Stores members
059                this.parent = parent;
060
061                // Configures chooser
062                setAcceptAllFileFilterUsed(false);
063
064                if (props != null) {
065                        // Loads file types
066                        String extension, description;
067                        for (int i = 0;
068                                (extension = props.getProperty("filetype" + i + ".extension")) != null
069                         && (description = props.getProperty("filetype" + i + ".description")) != null;
070                                        i++) {
071                                addChoosableFileFilter(new Filter(
072                                        new FilenameExtensionFilter(extension), description));
073                        }
074                        if (filters.size() > 0)
075                                setFileFilter(filters.get(0));
076
077                        // Loads current directory
078                        String currentDir = props.getProperty("recentfile0");
079                        if (currentDir != null)
080                                setCurrentDirectory(new File(currentDir));
081                }
082        }
083
084        /**
085         * Shows a file chooser and returns the file the user selected, if any.
086         */
087        public File getFileToOpen() {
088                if (showOpenDialog(parent) == JFileChooser.APPROVE_OPTION)
089                        return getChosenFile();
090                else
091                        return null;
092        }
093
094        /**
095         * Shows a file chooser and returns the file the user selected, if any.
096         */
097        public File getFileToSave() {
098                if (showSaveDialog(parent) == JFileChooser.APPROVE_OPTION)
099                        return getChosenFile();
100                else
101                        return null;
102        }
103
104        /**
105         * Shows a file chooser and returns the file the user selected, if any.
106         */
107        private File getChosenFile() {
108                File file = getSelectedFile();
109                String filename = file.getName();
110                if (filename.lastIndexOf('.') != -1) {
111                        // Checks if the file is acceptable by any of the filters.
112                        boolean filterAcceptable = filters.isEmpty();
113                        for (Filter filter : filters)
114                                if (filter.getFilter().accept(file, filename)) {
115                                        filterAcceptable = true;
116                                        break;
117                                }
118                        return file.isDirectory() || filterAcceptable ? file : null;
119                } else {
120                        // Appends default extension from the chosen filter
121                        FileFilter filter = getFileFilter();
122                        if (filter instanceof Filter) {
123                                FilenameFilter filenameFilter = ((Filter)filter).getFilter();
124                                if (filenameFilter instanceof FilenameExtensionFilter) {
125                                        String[] extensions = ((FilenameExtensionFilter)
126                                                filenameFilter).getExtensions();
127                                        return new File(file.getAbsolutePath() + "." + extensions[0]);
128                                }
129                        }
130                        return null;
131                }
132        }
133
134        public void addChoosableFileFilter(FileFilter filter) {
135                super.addChoosableFileFilter(filter);
136                if (filter instanceof Filter) filters.add((Filter)filter);
137        }
138
139        public void workbookCreated(SpreadsheetAppEvent event) {}
140
141        public void workbookLoaded(SpreadsheetAppEvent event) {
142                setCurrentDirectory(event.getFile());
143        }
144
145        public void workbookUnloaded(SpreadsheetAppEvent event) {}
146
147        public void workbookSaved(SpreadsheetAppEvent event) {
148                setCurrentDirectory(event.getFile());
149        }
150
151        /**
152         * A file filter for use in file choosers.
153         * @author Einar Pehrson
154         */
155        public static class Filter extends FileFilter {
156
157                /** The filename filter used to determine which files to accept. */
158                private FilenameFilter filter;
159
160                /** The description of the filter. */
161                private String description;
162
163                /**
164                 * Creates a new filter, using the given filename filter to determine which
165                 * files to accept.
166                 * @param filter the filename filter used to determine which files to accept
167                 * @param description the description of the filter
168                 */
169                public Filter(FilenameFilter filter, String description) {
170                        this.filter = filter;
171                        this.description = description;
172                }
173
174                public boolean accept(File f) {
175                        return f != null && (f.isDirectory() || filter.accept(f, f.getName()));
176                }
177
178                /**
179                 * Returns the filename filter used to determine which files to accept.
180                 * @return the filename filter
181                 */
182                public FilenameFilter getFilter() {
183                        return filter;
184                }
185
186                /**
187                 * Returns the description of the filter
188                 * @return the description of the filter
189                 */
190                public String getDescription() {
191                        return description;
192                }
193        }
194}