// Copyrigh 2003-2007, FreeHEP. package org.freehep.util.export; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Properties; import java.util.Vector; import javax.swing.DefaultListCellRenderer; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingConstants; import org.freehep.swing.ErrorDialog; import org.freehep.swing.layout.TableLayout; /** * An "Export" dialog for saving components as graphic files. * * As of August 2007, Markus Strauch added the following methods: * * <ul> * <li>{@linkplain #addExportDialogListener(ExportDialogListener)}</li> * <li>{@linkplain #removeExportDialogListener(ExportDialogListener)}</li> * <ul> * * An <tt>ExportDialogListener</tt> has a single method, * <tt>writeFile(String type)</tt> that is called when the export format is * fixed and right before exporting starts. * * @author tonyj * @version $Id: ExportDialog.java,v 1.1.1.1 2009-11-19 14:41:04 strauch Exp $ */ public class ExportDialog extends JOptionPane { private static final String rootKey = ExportDialog.class.getName(); private static final String SAVE_AS_TYPE = rootKey + ".SaveAsType"; private static final String SAVE_AS_FILE = rootKey + ".SaveAsFile"; /** * Set the Properties object to be used for storing/restoring user * preferences. If not called user preferences will not be saved. * * @param properties * The Properties to use for user preferences */ public void setUserProperties(Properties properties) { props = properties; } /** * Register an export file type. */ public void addExportFileType(ExportFileType fileType) { list.addElement(fileType); } public void addAllExportFileTypes() { ExportFileTypeGroups groups = new ExportFileTypeGroups(ExportFileType .getExportFileTypes()); for (Iterator i = groups.getGroupNames().iterator(); i.hasNext();) { String group = (String) i.next(); List exportTypes = groups.getExportFileTypes(group); if (exportTypes.size() > 0) { list.add(new JLabel(groups.getLabel(group), SwingConstants.CENTER)); Collections.sort(exportTypes); for (Iterator j = exportTypes.iterator(); j.hasNext();) { addExportFileType((ExportFileType) j.next()); } } } } /** * Creates a new instance of ExportDialog with all the standard export * filetypes. */ public ExportDialog() { this(null); } /** * Creates a new instance of ExportDialog with all the standard export * filetypes. * * @param creator * The "creator" to be written into the header of the file (may * be null) */ public ExportDialog(String creator) { this(creator, true); } /** * Creates a new instance of ExportDialog. * * @param creator * The "creator" to be written into the header of the file (may * be null) * @param addAllExportFileTypes * If true registers all the standard export filetypes */ public ExportDialog(String creator, boolean addAllExportFileTypes) { super(null, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION); this.creator = creator; listeners = new LinkedList<ExportDialogListener>(); try { baseDir = System.getProperty("user.home"); } catch (SecurityException x) { trusted = false; } ButtonListener bl = new ButtonListener(); JPanel panel = new JPanel(new TableLayout()); if (trusted) { panel.add("* * [5 5 5 5] w", file); panel.add("* * * 1 [5 5 5 5] wh", browse); } type = new JComboBox(list); type.setMaximumRowCount(16); // rather than 8 panel.add("* * 1 1 [5 5 5 5] w", type); panel.add("* * * 1 [5 5 5 5] wh", advanced); browse.addActionListener(bl); advanced.addActionListener(bl); type.setRenderer(new SaveAsRenderer()); type.addActionListener(bl); setMessage(panel); if (addAllExportFileTypes) addAllExportFileTypes(); } /** * Show the dialog. * * @param parent * The parent for the dialog * @param title * The title for the dialog * @param target * The component to be saved. * @param size * The target size to be used for export. * @param defFile * The default file name to use. */ public void showExportDialog(Component parent, String title, Component target, Dimension size, String defFile) { // NOTE: same, and used in AbstractExportFileType props.setProperty("size-w", String.valueOf(size.width)); props.setProperty("size-h", String.valueOf(size.height)); showExportDialog(parent, title, target, defFile); } /** * Show the dialog. * * @param parent * The parent for the dialog * @param title * The title for the dialog * @param target * The component to be saved. * @param defFile * The default file name to use. */ public void showExportDialog(Component parent, String title, Component target, String defFile) { this.component = target; // NOTE: a label is always first if (list.size() > 0) type.setSelectedIndex(1); String dType = props.getProperty(SAVE_AS_TYPE); if (dType != null) { for (int i = 0; i < list.size(); i++) { Object obj = list.elementAt(i); if (obj instanceof ExportFileType) { ExportFileType saveAs = (ExportFileType) obj; if (saveAs.getFileFilter().getDescription().equals(dType)) { type.setSelectedItem(saveAs); break; } } } } advanced.setEnabled(currentType() != null && currentType().hasOptionPanel()); if (trusted) { String saveFile = props.getProperty(SAVE_AS_FILE); if (saveFile != null) { baseDir = new File(saveFile).getParent(); defFile = saveFile; } else { defFile = baseDir + File.separator + defFile; } File f = new File(defFile); if (currentType() != null) f = currentType().adjustFilename(f, currentType().getFileExtension(f), props); file.setText(f.toString()); } else { file.setEnabled(false); browse.setEnabled(false); } JDialog dlg = createDialog(parent, title); dlg.pack(); dlg.setVisible(true); } private ExportFileType currentType() { return (ExportFileType) type.getSelectedItem(); } /** * Called to open a "file browser". Override this method to provide special * handling (e.g. in a WebStart app) * * @return The full name of the selected file, or null if no file selected */ protected String selectFile() { JFileChooser dlg = new JFileChooser(); String f = file.getText(); if (f != null) dlg.setSelectedFile(new File(f)); dlg.setFileFilter(currentType().getFileFilter()); if (dlg.showDialog(this, "Select") == JFileChooser.APPROVE_OPTION) { return dlg.getSelectedFile().getAbsolutePath(); } else { return null; } } /** * Called to acually write out the file. Override this method to provide * special handling (e.g. in a WebStart app) * * @return true if the file was written, or false to cancel operation */ protected boolean writeFile(Component component, ExportFileType t) throws IOException { File f = new File(file.getText()); if (f.exists()) { int ok = JOptionPane.showConfirmDialog(this, "Replace existing file?"); if (ok != JOptionPane.OK_OPTION) return false; } String extension = t.getExtensions()[0]; for (ExportDialogListener listener : listeners) { listener.writeFile(extension); } t.exportToFile(f, component, this, props, creator); props.put(SAVE_AS_FILE, file.getText()); props.put(SAVE_AS_TYPE, currentType().getFileFilter().getDescription()); return true; } public void setValue(Object value) { if (value instanceof Integer && ((Integer) value).intValue() == OK_OPTION) { try { if (!writeFile(component, currentType())) return; } catch (Throwable x) { ErrorDialog.showErrorDialog(this, "Error writing graphics file", x); return; } } super.setValue(value); } private String creator; private JButton browse = new JButton("Browse..."); private JButton advanced = new JButton("Options..."); private JTextField file = new JTextField(40); private JComboBox type; private Component component; private boolean trusted = true; private Vector list = new Vector(); private Properties props = new Properties(); private String baseDir = null; private List<ExportDialogListener> listeners; public void addExportDialogListener(ExportDialogListener listener) { listeners.add(listener); } public void removeExportDialogListener(ExportDialogListener listener) { listeners.remove(listener); } private class ButtonListener implements ActionListener { private ExportFileType previousType = null; public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == browse) { String fileName = selectFile(); if (fileName != null) { if (currentType() != null) { File f = new File(fileName); currentType().adjustFilename(f, currentType().getFileExtension(f), props); file.setText(f.getPath()); } else { file.setText(fileName); } } } else if (source == advanced) { if (currentType() != null) { JPanel panel = currentType().createOptionPanel(props); int rc = JOptionPane.showConfirmDialog(ExportDialog.this, panel, "Options for " + currentType().getDescription(), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); if (rc == JOptionPane.OK_OPTION) { currentType().applyChangedOptions(panel, props); File f1 = new File(file.getText()); File f2 = currentType().adjustFilename(f1, currentType().getFileExtension(f1), props); if (!f1.equals(f2) && file.isEnabled()) file.setText(f2.toString()); } } } else if (source == type) { if (type.getSelectedItem() instanceof ExportFileType) { if (previousType == null) previousType = currentType(); advanced.setEnabled(currentType().hasOptionPanel()); File f1 = new File(file.getText()); File f2 = currentType().adjustFilename(f1, previousType.getFileExtension(f1), props); if (!f1.equals(f2) && file.isEnabled()) file.setText(f2.toString()); previousType = currentType(); } else { // keep old selection type.setSelectedItem(previousType); } } } } private static class SaveAsRenderer extends DefaultListCellRenderer { public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof ExportFileType) { this.setText(((ExportFileType) value).getFileFilter() .getDescription()); } else if (value instanceof JLabel) { return (Component) value; } return this; } } }