// 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;
}
}
}