Java tutorial
/* * 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 3 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, see <http://www.gnu.org/licenses/>. */ /* * ConverterFileChooser.java * Copyright (C) 2006-2012 University of Waikato, Hamilton, New Zealand */ package weka.gui; import weka.core.Capabilities; import weka.core.Instances; import weka.core.WekaPackageClassLoaderManager; import weka.core.converters.AbstractFileLoader; import weka.core.converters.AbstractFileSaver; import weka.core.converters.AbstractLoader; import weka.core.converters.AbstractSaver; import weka.core.converters.ConverterResources; import weka.core.converters.ConverterUtils; import weka.core.converters.FileSourcedConverter; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.filechooser.FileFilter; import java.awt.BorderLayout; import java.awt.Component; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.Vector; /** * A specialized JFileChooser that lists all available file Loaders and Savers. * To list only savers that can handle the data that is about to be saved, one * can set a Capabilities filter. * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision$ * @see #setCapabilitiesFilter(Capabilities) */ public class ConverterFileChooser extends WekaFileChooser { /** for serialization. */ private static final long serialVersionUID = -5373058011025481738L; /** unhandled type of dialog. */ public final static int UNHANDLED_DIALOG = 0; /** the loader dialog. */ public final static int LOADER_DIALOG = 1; /** the saver dialog. */ public final static int SAVER_DIALOG = 2; /** the file filters for the loaders. */ protected static Vector<ExtensionFileFilter> m_LoaderFileFilters; /** the file filters for the savers. */ protected static Vector<ExtensionFileFilter> m_SaverFileFilters; /** the type of dialog to display. */ protected int m_DialogType; /** the converter that was chosen by the user. */ protected Object m_CurrentConverter; /** the propertychangelistener. */ protected PropertyChangeListener m_Listener; /** the last filter that was used for opening/saving. */ protected FileFilter m_LastFilter; /** the Capabilities filter for the savers. */ protected Capabilities m_CapabilitiesFilter; /** * whether to popup a dialog in case the file already exists (only save * dialog). */ protected boolean m_OverwriteWarning = true; /** whether the file to be opened must exist (only open dialog). */ protected boolean m_FileMustExist = true; /** the checkbox for bringing up the GenericObjectEditor. */ protected JCheckBox m_CheckBoxOptions; /** the GOE for displaying the options of a loader/saver. */ protected GenericObjectEditor m_Editor; /** whether the GOE was OKed or Canceled. */ protected int m_EditorResult; /** * whether to display only core converters (hardcoded in ConverterUtils). * Necessary for RMI/Remote Experiments for instance. * * @see weka.core.converters.ConverterResources#CORE_FILE_LOADERS * @see weka.core.converters.ConverterResources#CORE_FILE_SAVERS */ protected boolean m_CoreConvertersOnly = false; static { initDefaultFilters(); } /** * Initialize the default set of filters for loaders and savers */ public static void initDefaultFilters() { ConverterUtils.initialize(); initFilters(true, ConverterUtils.getFileLoaders()); initFilters(false, ConverterUtils.getFileSavers()); } /** * onstructs a FileChooser pointing to the user's default directory. */ public ConverterFileChooser() { super(); } /** * Constructs a FileChooser using the given File as the path. * * @param currentDirectory the path to start in */ public ConverterFileChooser(File currentDirectory) { super(currentDirectory); } /** * Constructs a FileChooser using the given path. * * @param currentDirectory the path to start in */ public ConverterFileChooser(String currentDirectory) { super(currentDirectory); } /** * Further initializations. */ protected void initialize() { JPanel panel; super.initialize(); panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); m_AccessoryPanel.add(panel, BorderLayout.NORTH); m_CheckBoxOptions = new JCheckBox("Invoke options dialog"); m_CheckBoxOptions.setMnemonic('I'); panel.add(m_CheckBoxOptions); m_Editor = new GenericObjectEditor(false); ((GenericObjectEditor.GOEPanel) m_Editor.getCustomEditor()).addOkListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { m_EditorResult = JFileChooser.APPROVE_OPTION; m_CurrentConverter = m_Editor.getValue(); // thanks to serialization and transient readers/streams, we have // to set the file again to initialize the converter again try { ((FileSourcedConverter) m_CurrentConverter) .setFile(((FileSourcedConverter) m_CurrentConverter).retrieveFile()); } catch (Exception ex) { // ignored } } }); ((GenericObjectEditor.GOEPanel) m_Editor.getCustomEditor()).addCancelListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { m_EditorResult = JFileChooser.CANCEL_OPTION; } }); } /** * filters out all non-core loaders if only those should be displayed. * * @param list the list of filters to check * @return the filtered list of filters * @see #m_CoreConvertersOnly */ protected Vector<ExtensionFileFilter> filterNonCoreLoaderFileFilters(Vector<ExtensionFileFilter> list) { Vector<ExtensionFileFilter> result; int i; ExtensionFileFilter filter; AbstractLoader loader; if (!getCoreConvertersOnly()) { result = list; } else { result = new Vector<ExtensionFileFilter>(); for (i = 0; i < list.size(); i++) { filter = list.get(i); loader = ConverterUtils.getLoaderForExtension(filter.getExtensions()[0]); if (ConverterResources.isCoreFileLoader(loader.getClass().getName())) { result.add(filter); } } } return result; } /** * filters out all non-core savers if only those should be displayed. * * @param list the list of filters to check * @return the filtered list of filters * @see #m_CoreConvertersOnly */ protected Vector<ExtensionFileFilter> filterNonCoreSaverFileFilters(Vector<ExtensionFileFilter> list) { Vector<ExtensionFileFilter> result; int i; ExtensionFileFilter filter; AbstractSaver saver; if (!getCoreConvertersOnly()) { result = list; } else { result = new Vector<ExtensionFileFilter>(); for (i = 0; i < list.size(); i++) { filter = list.get(i); saver = ConverterUtils.getSaverForExtension(filter.getExtensions()[0]); if (ConverterResources.isCoreFileSaver(saver.getClass().getName())) { result.add(filter); } } } return result; } /** * filters the list of file filters according to the currently set. * Capabilities * * @param list the filters to check * @return the filtered list of filters */ protected Vector<ExtensionFileFilter> filterSaverFileFilters(Vector<ExtensionFileFilter> list) { Vector<ExtensionFileFilter> result; int i; ExtensionFileFilter filter; AbstractSaver saver; if (m_CapabilitiesFilter == null) { result = list; } else { result = new Vector<ExtensionFileFilter>(); for (i = 0; i < list.size(); i++) { filter = list.get(i); saver = ConverterUtils.getSaverForExtension(filter.getExtensions()[0]); if (saver.getCapabilities().supports(m_CapabilitiesFilter)) { result.add(filter); } } } return result; } /** * initializes the ExtensionFileFilters. * * @param loader if true then the loader filter are initialized * @param classnames the classnames of the converters */ protected static void initFilters(boolean loader, Vector<String> classnames) { int i; int n; String classname; Class<?> cls; String[] ext; String desc; FileSourcedConverter converter; ExtensionFileFilter filter; if (loader) { m_LoaderFileFilters = new Vector<ExtensionFileFilter>(); } else { m_SaverFileFilters = new Vector<ExtensionFileFilter>(); } for (i = 0; i < classnames.size(); i++) { classname = classnames.get(i); // get data from converter try { cls = WekaPackageClassLoaderManager.forName(classname); converter = (FileSourcedConverter) cls.newInstance(); ext = converter.getFileExtensions(); desc = converter.getFileDescription(); } catch (Exception e) { cls = null; converter = null; ext = new String[0]; desc = ""; } if (converter == null) { continue; } // loader? if (loader) { for (n = 0; n < ext.length; n++) { filter = new ExtensionFileFilter(ext[n], desc + " (*" + ext[n] + ")"); m_LoaderFileFilters.add(filter); } } else { for (n = 0; n < ext.length; n++) { filter = new ExtensionFileFilter(ext[n], desc + " (*" + ext[n] + ")"); m_SaverFileFilters.add(filter); } } } } /** * initializes the GUI. * * @param dialogType the type of dialog to setup the GUI for */ protected void initGUI(int dialogType) { Vector<ExtensionFileFilter> list; int i; boolean acceptAll; // backup current state acceptAll = isAcceptAllFileFilterUsed(); // setup filters resetChoosableFileFilters(); setAcceptAllFileFilterUsed(acceptAll); if (dialogType == LOADER_DIALOG) { list = filterNonCoreLoaderFileFilters(m_LoaderFileFilters); } else { list = filterSaverFileFilters(filterNonCoreSaverFileFilters(m_SaverFileFilters)); } for (i = 0; i < list.size(); i++) { addChoosableFileFilter(list.get(i)); } if (list.size() > 0) { if ((m_LastFilter == null) || (!list.contains(m_LastFilter))) { setFileFilter(list.get(0)); } else { setFileFilter(m_LastFilter); } } // listener if (m_Listener != null) { removePropertyChangeListener(m_Listener); } m_Listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { // filter changed if (evt.getPropertyName().equals(FILE_FILTER_CHANGED_PROPERTY)) { updateCurrentConverter(); } } }; addPropertyChangeListener(m_Listener); // initial setup if (dialogType == LOADER_DIALOG) { m_Editor.setClassType(AbstractFileLoader.class); m_Editor.setValue(new weka.core.converters.ArffLoader()); } else { m_Editor.setClassType(AbstractFileSaver.class); m_Editor.setValue(new weka.core.converters.ArffSaver()); } updateCurrentConverter(); } /** * sets the capabilities that the savers must have. use null if all should be * listed. * * @param value the minimum Capabilities the savers must have */ public void setCapabilitiesFilter(Capabilities value) { m_CapabilitiesFilter = (Capabilities) value.clone(); } /** * returns the capabilities filter for the savers, can be null if all are * listed. * * @return the minimum Capabilities the savers must have */ public Capabilities getCapabilitiesFilter() { if (m_CapabilitiesFilter != null) { return (Capabilities) m_CapabilitiesFilter.clone(); } else { return null; } } /** * Whether a warning is popped up if the file that is to be saved already * exists (only save dialog). * * @param value if true a warning will be popup */ public void setOverwriteWarning(boolean value) { m_OverwriteWarning = value; } /** * Returns whether a popup appears with a warning that the file already exists * (only save dialog). * * @return true if a warning pops up */ public boolean getOverwriteWarning() { return m_OverwriteWarning; } /** * Whether the selected file must exst (only open dialog). * * @param value if true the file must exist */ public void setFileMustExist(boolean value) { m_FileMustExist = value; } /** * Returns whether the selected file must exist (only open dialog). * * @return true if the file must exist */ public boolean getFileMustExist() { return m_FileMustExist; } /** * Whether to display only the hardocded core converters. Necessary for * RMI/Remote Experiments (dynamic class discovery doesn't work there!). * * @param value if true only the core converters will be displayed * @see #m_CoreConvertersOnly */ public void setCoreConvertersOnly(boolean value) { m_CoreConvertersOnly = value; } /** * Returns whether only the hardcoded core converters are displayed. Necessary * for RMI/REmote Experiments (dynamic class discovery doesn't work there!). * * @return true if the file must exist * @see #m_CoreConvertersOnly */ public boolean getCoreConvertersOnly() { return m_CoreConvertersOnly; } /** * Pops a custom file chooser dialog with a custom approve button. Throws an * exception, if the dialog type is UNHANDLED_DIALOG. * * @param parent the parent of this dialog * @param approveButtonText the text for the OK button * @return the user's action */ @Override public int showDialog(Component parent, String approveButtonText) { if (m_DialogType == UNHANDLED_DIALOG) { throw new IllegalStateException("Either use showOpenDialog or showSaveDialog!"); } else { return super.showDialog(parent, approveButtonText); } } /** * Pops up an "Open File" file chooser dialog. * * @param parent the parent of this file chooser * @return the result of the user's action */ @Override public int showOpenDialog(Component parent) { m_DialogType = LOADER_DIALOG; m_CurrentConverter = null; initGUI(LOADER_DIALOG); int result = super.showOpenDialog(parent); m_DialogType = UNHANDLED_DIALOG; removePropertyChangeListener(m_Listener); // do we have to add the extension? if ((result == APPROVE_OPTION) && (getSelectedFile().isFile())) { if (getFileFilter() instanceof ExtensionFileFilter) { String filename = getSelectedFile().getAbsolutePath(); String[] extensions = ((ExtensionFileFilter) getFileFilter()).getExtensions(); if (!filename.endsWith(extensions[0])) { filename += extensions[0]; setSelectedFile(new File(filename)); } } } // does file exist? if ((result == APPROVE_OPTION) && (getFileMustExist()) && (getSelectedFile().isFile()) && (!getSelectedFile().exists())) { int retVal = JOptionPane.showConfirmDialog(parent, "The file '" + getSelectedFile() + "' does not exist - please select again!"); if (retVal == JOptionPane.OK_OPTION) { result = showOpenDialog(parent); } else { result = CANCEL_OPTION; } } if (result == APPROVE_OPTION) { m_LastFilter = getFileFilter(); configureCurrentConverter(LOADER_DIALOG); // bring up options dialog? if (m_CheckBoxOptions.isSelected() && m_CurrentConverter != null) { m_EditorResult = JFileChooser.CANCEL_OPTION; m_Editor.setValue(m_CurrentConverter); PropertyDialog pd; if (PropertyDialog.getParentDialog(this) != null) { pd = new PropertyDialog(PropertyDialog.getParentDialog(this), m_Editor); } else { pd = new PropertyDialog(PropertyDialog.getParentFrame(this), m_Editor); } pd.setVisible(true); result = m_EditorResult; } } return result; } /** * Pops up an "Save File" file chooser dialog. * * @param parent the parent of this file chooser * @return the result of the user's action */ @Override public int showSaveDialog(Component parent) { m_DialogType = SAVER_DIALOG; m_CurrentConverter = null; initGUI(SAVER_DIALOG); boolean acceptAll = isAcceptAllFileFilterUsed(); // using "setAcceptAllFileFilterUsed" messes up the currently selected // file filter/file, hence backup/restore of currently selected // file filter/file FileFilter currentFilter = getFileFilter(); File currentFile = getSelectedFile(); setAcceptAllFileFilterUsed(false); setFileFilter(currentFilter); setSelectedFile(currentFile); int result = super.showSaveDialog(parent); // do we have to add the extension? if (result == APPROVE_OPTION) { if (getFileFilter() instanceof ExtensionFileFilter) { String filename = getSelectedFile().getAbsolutePath(); String[] extensions = ((ExtensionFileFilter) getFileFilter()).getExtensions(); if (!filename.endsWith(extensions[0])) { filename += extensions[0]; setSelectedFile(new File(filename)); } } } // using "setAcceptAllFileFilterUsed" messes up the currently selected // file filter/file, hence backup/restore of currently selected // file filter/file currentFilter = getFileFilter(); currentFile = getSelectedFile(); setAcceptAllFileFilterUsed(acceptAll); setFileFilter(currentFilter); setSelectedFile(currentFile); m_DialogType = UNHANDLED_DIALOG; removePropertyChangeListener(m_Listener); // overwrite the file? if ((result == APPROVE_OPTION) && (getOverwriteWarning()) && (getSelectedFile().exists())) { int retVal = JOptionPane.showConfirmDialog(parent, "The file '" + getSelectedFile() + "' already exists - overwrite it?"); if (retVal == JOptionPane.OK_OPTION) { result = APPROVE_OPTION; } else if (retVal == JOptionPane.NO_OPTION) { result = showSaveDialog(parent); } else { result = CANCEL_OPTION; } } if (result == APPROVE_OPTION) { m_LastFilter = getFileFilter(); // configureCurrentConverter(SAVER_DIALOG); // bring up options dialog? if (m_CheckBoxOptions.isSelected()) { m_EditorResult = JFileChooser.CANCEL_OPTION; m_Editor.setValue(m_CurrentConverter); PropertyDialog pd; if (PropertyDialog.getParentDialog(this) != null) { pd = new PropertyDialog(PropertyDialog.getParentDialog(this), m_Editor); } else { pd = new PropertyDialog(PropertyDialog.getParentFrame(this), m_Editor); } pd.setVisible(true); result = m_EditorResult; // configureCurrentConverter(SAVER_DIALOG); } } return result; } /** * returns the loader that was chosen by the user, can be null in case the * user aborted the dialog or the save dialog was shown. * * @return the chosen loader, if any */ public AbstractFileLoader getLoader() { configureCurrentConverter(LOADER_DIALOG); if (m_CurrentConverter instanceof AbstractFileSaver) { return null; } else { return (AbstractFileLoader) m_CurrentConverter; } } /** * returns the saver that was chosen by the user, can be null in case the user * aborted the dialog or the open dialog was shown. * * @return the chosen saver, if any */ public AbstractFileSaver getSaver() { configureCurrentConverter(SAVER_DIALOG); if (m_CurrentConverter instanceof AbstractFileLoader) { return null; } else { return (AbstractFileSaver) m_CurrentConverter; } } /** * sets the current converter according to the current filefilter. */ protected void updateCurrentConverter() { String[] extensions; Object newConverter; if (getFileFilter() == null) { return; } if (!isAcceptAllFileFilterUsed()) { // determine current converter extensions = ((ExtensionFileFilter) getFileFilter()).getExtensions(); if (m_DialogType == LOADER_DIALOG) { newConverter = ConverterUtils.getLoaderForExtension(extensions[0]); } else { newConverter = ConverterUtils.getSaverForExtension(extensions[0]); } try { if (m_CurrentConverter == null) { m_CurrentConverter = newConverter; } else { if (!m_CurrentConverter.getClass().equals(newConverter.getClass())) { m_CurrentConverter = newConverter; } } } catch (Exception e) { m_CurrentConverter = null; e.printStackTrace(); } } else { m_CurrentConverter = null; } } /** * configures the current converter. * * @param dialogType the type of dialog to configure for */ protected void configureCurrentConverter(int dialogType) { String filename; File currFile; if ((getSelectedFile() == null) || (getSelectedFile().isDirectory())) { return; } filename = getSelectedFile().getAbsolutePath(); if (m_CurrentConverter == null) { if (dialogType == LOADER_DIALOG) { m_CurrentConverter = ConverterUtils.getLoaderForFile(filename); } else if (dialogType == SAVER_DIALOG) { m_CurrentConverter = ConverterUtils.getSaverForFile(filename); } else { throw new IllegalStateException("Cannot determine loader/saver!"); } // none found? if (m_CurrentConverter == null) { return; } } try { currFile = ((FileSourcedConverter) m_CurrentConverter).retrieveFile(); if ((currFile == null) || (!currFile.getAbsolutePath().equals(filename))) { ((FileSourcedConverter) m_CurrentConverter).setFile(new File(filename)); } } catch (Exception e) { e.printStackTrace(); } } /** * For testing the file chooser. * * @param args the commandline options - ignored * @throws Exception if something goes wrong with loading/saving */ public static void main(String[] args) throws Exception { ConverterFileChooser fc; int retVal; AbstractFileLoader loader; AbstractFileSaver saver; Instances data; fc = new ConverterFileChooser(); retVal = fc.showOpenDialog(null); // load file if (retVal == ConverterFileChooser.APPROVE_OPTION) { loader = fc.getLoader(); data = loader.getDataSet(); retVal = fc.showSaveDialog(null); // save file if (retVal == ConverterFileChooser.APPROVE_OPTION) { saver = fc.getSaver(); saver.setInstances(data); saver.writeBatch(); } else { System.out.println("Saving aborted!"); } } else { System.out.println("Loading aborted!"); } } }