// // @(#)XJFileChooser.java 7/2003 // // Copyright 2003 Zachary DelProposto. All rights reserved. // Use is subject to license terms. // // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // Or from http://www.gnu.org/ // package dip.gui.swing; import dip.misc.Utils; import dip.misc.SimpleFileFilter; import dip.misc.Log; import java.awt.Component; import java.io.File; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileFilter; /** * A simplified and extended JFileChooser for single-file (only!) * selections. It is also cached, so that it displays faster. * <p> * SimpleFileFilter support is integrated, so that file extensions * are automatically appended (unless "all files" is selected). * <p> * Futhermore, if saving a file, checking is done to determine * if a file will be overwritten; if so, a confirmation dialog * is displayed. * <p> */ public class XJFileChooser { // constants private static final String OVERWRITE_TEXT = "XJFileChooser.dialog.overwrite.text.location"; private static final String OVERWRITE_TITLE = "XJFileChooser.dialog.overwrite.title"; public static final String BTN_DIR_SELECT = "XJFileChooser.button.dir.select"; private static final String TITLE_SAVE_AS = "XJFileChooser.title.saveas"; /* //simple test... public static void main(String[] dsf) throws Exception { System.out.println("hello"); XJFileChooser c = XJFileChooser.getXJFileChooser(); c.addFileFilter(SimpleFileFilter.JPG_FILTER); System.out.println(c.displayOpen(null)); c.dispose(); c = XJFileChooser.getXJFileChooser(); c.addFileFilter(SimpleFileFilter.PDF_FILTER); c.addFileFilter(SimpleFileFilter.TXT_FILTER); System.out.println(c.displaySave(null)); c.dispose(); c = XJFileChooser.getXJFileChooser(); c.addFileFilter(SimpleFileFilter.PNG_FILTER); c.addFileFilter(SimpleFileFilter.TXT_FILTER); System.out.println(c.displaySaveAs(null)); c.dispose(); // this shoudl fail (no get() called) c.displaySaveAs(null); // this should fail c.displaySaveAs(null); } */ // class variables private static XJFileChooser instance = null; private static SwingWorker loader = null; private static int refcount = 0; // instance variables private final CheckedJFileChooser chooser; /** Constructor */ private XJFileChooser() { chooser = new CheckedJFileChooser(); chooser.setAcceptAllFileFilterUsed(true); }// XJFileChooser() /** * Can be used to initialize the XJFileChooser when called * to provide faster response later */ public static synchronized void init() { if(instance == null) { if(loader == null) { loader = new SwingWorker() { public Object construct() { long time = System.currentTimeMillis(); XJFileChooser xjf = new XJFileChooser(); Log.printTimed(time, "XJFileChooser construct() complete: "); return xjf; }// construct() }; loader.start(Thread.MIN_PRIORITY); } else { instance = (XJFileChooser) loader.get(); instance = null; } } }// init() /** * Gets the XJFileChooser (only one exists -- this must be * enforced by you!). * <p> * The file filters are reset when this is called, which * means that (usually) only the AcceptAll file filter * (which is not a SimpleFileFilter) remains. */ public static synchronized XJFileChooser getXJFileChooser() { if(instance == null) { instance = new XJFileChooser(); } refcount++; if(refcount > 1) { throw new IllegalStateException("cannot re-use getXJFileChooser()"); } instance.reset(); return instance; }// getXJFileChooser() /** * Disposes the in-use XJFileChooser. This should ALWAYS be called * after a display() method has been called. The number of dispose() * and getXJFileChooser() methods should be balanced. */ public static synchronized void dispose() { refcount--; if(refcount < 0) { throw new IllegalStateException("XJFileChooser too many dispose() calls"); } }// dispose() /** * Adds a SimpleFileFilter to the list of available * file filters. */ public void addFileFilter(SimpleFileFilter filter) { chooser.addChoosableFileFilter(filter); }// addFileFilter() /** * Sets the default file filter. If null, sets the * 'accept all' file filter. */ public void setFileFilter(SimpleFileFilter filter) { if(filter != null) { chooser.setFileFilter(filter); } else { chooser.setFileFilter(chooser.getAcceptAllFileFilter()); } }// addFileFilter() /** * Set the current directory. May be set to null ('home' directory) */ public void setCurrentDirectory(File file) { chooser.setCurrentDirectory(file); }// setCurrentDirectory() /** * Sets the suggested file name. By default, no file name * is suggested. */ public void setSelectedFile(File file) { if(file == null) { chooser.setSelectedFile(new File("")); } else { chooser.setSelectedFile(file); } }// setSuggestedFileName() /** * Display the file chooser, with the given title and Accept button * text. No file filters are added. The type (JFileChooser.OPEN_DIALOG or * SAVE_DIALOG) must be specified. If the acceptButtonText and/or title is null, the default * button text (for OPEN_DIALOG or SAVE_DIALOG) and/or title is used. * * @return the selected File, or null */ public File display(Component parent, String title, String acceptButtonText, int type, int mode) { synchronized(XJFileChooser.class) { if(refcount != 1) { throw new IllegalStateException("dipose / get not balanced"); } } if(type != JFileChooser.OPEN_DIALOG && type != JFileChooser.SAVE_DIALOG) { throw new IllegalArgumentException("invalid type"); } chooser.setDialogType(type); if(acceptButtonText != null) { chooser.setApproveButtonText(acceptButtonText); } if(title != null) { chooser.setDialogTitle(title); } chooser.setFileSelectionMode(mode); if(chooser.showDialog(parent, null) == JFileChooser.APPROVE_OPTION) { if(chooser.getDialogType() != JFileChooser.OPEN_DIALOG) { return fixFileExtension(chooser.getFileFilter(), chooser.getSelectedFile()); } else { return chooser.getSelectedFile(); } } return null; }// display() /** Appends an extension, if appropriate */ private File fixFileExtension(FileFilter ff, File file) { if(ff instanceof SimpleFileFilter) { return ((SimpleFileFilter) ff).appendExtension(file); } return file; }// fixFileExtension() /** * The typical "Open" dialog. No filters are added. * * @return the selected File, or null */ public File displayOpen(Component parent) { return display(parent, null, null, JFileChooser.OPEN_DIALOG, JFileChooser.FILES_ONLY); }// displayOpen() /** * The typical "Open" dialog. No filters are added. * A title may be specified. * * @return the selected File, or null */ public File displayOpen(Component parent, String title) { return display(parent, title, null, JFileChooser.OPEN_DIALOG, JFileChooser.FILES_ONLY); }// displayOpen() /** * The typical "Save" dialog. No filters are added. * * @return the selected File, or null */ public File displaySave(Component parent) { return display(parent, null, null, JFileChooser.SAVE_DIALOG, JFileChooser.FILES_ONLY); }// displaySave() /** * The typical "Save" dialog. No filters are added. * A different title may be specified. * * @return the selected File, or null */ public File displaySave(Component parent, String title) { return display(parent, title, null, JFileChooser.SAVE_DIALOG, JFileChooser.FILES_ONLY); }// displaySave() /** * The typical "Save As" dialog. No filters are added. * * @return the selected File, or null */ public File displaySaveAs(Component parent) { final String title = Utils.getLocalString(TITLE_SAVE_AS); return display(parent, title, null, JFileChooser.SAVE_DIALOG, JFileChooser.FILES_ONLY); }// displaySaveAs() /** * Display a filechooser that only allows the selection * of a single directory. * * @return the selected directory, or null */ public File displaySelectDir(Component parent, String title) { final String selectText = Utils.getLocalString(BTN_DIR_SELECT); return display(parent, title, selectText, JFileChooser.OPEN_DIALOG, JFileChooser.DIRECTORIES_ONLY); }// displaySelectDir() /** * resets the XJFileChooser to its default state * */ private void reset() { chooser.setSelectedFile(new File("")); chooser.resetChoosableFileFilters(); chooser.setMultiSelectionEnabled(false); chooser.setCurrentDirectory(null); }// reset() /** * Extends JFileChooser; displays a confirmation popup * if we are a SAVE dialog, and the file already exists. * This prevents users from accidentally overwriting * files. * */ private class CheckedJFileChooser extends JFileChooser { public CheckedJFileChooser() { super((File) null); } /** Override to check for overwrite confirmation */ public void approveSelection() { if(getDialogType() != JFileChooser.OPEN_DIALOG) { File selectedFile = fixFileExtension(chooser.getFileFilter(), chooser.getSelectedFile()); if(selectedFile != null) { if( selectedFile.exists() ) { String message = Utils.getText(Utils.getLocalString(OVERWRITE_TEXT), selectedFile.getName()); int result = JOptionPane.showConfirmDialog(getParent(), message, Utils.getLocalString(OVERWRITE_TITLE), JOptionPane.YES_NO_OPTION ); if(result != JOptionPane.YES_OPTION) { cancelSelection(); return; } // fall thru } } } super.approveSelection(); }// approveSelection() }// inner class CheckedJFileChooser }// class XJFileChooser