/* * BeautiFrame.java * * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ /* * BeautiFrame.java * * (c) 2002-2005 BEAST Development Core Team * * This package may be distributed under the * Lesser Gnu Public Licence (LGPL) */ package dr.app.beauti; import dr.app.beauti.ancestralStatesPanel.AncestralStatesPanel; import dr.app.beauti.clockModelsPanel.ClockModelsPanel; import dr.app.beauti.components.ComponentFactory; import dr.app.beauti.components.ancestralstates.AncestralStatesComponentFactory; import dr.app.beauti.components.continuous.ContinuousComponentFactory; import dr.app.beauti.components.discrete.DiscreteTraitsComponentFactory; import dr.app.beauti.components.dollo.DolloComponentFactory; import dr.app.beauti.components.hpm.HierarchicalModelComponentFactory; import dr.app.beauti.components.linkedparameters.LinkedParameterComponentFactory; import dr.app.beauti.components.marginalLikelihoodEstimation.MarginalLikelihoodEstimationComponentFactory; import dr.app.beauti.components.sequenceerror.SequenceErrorModelComponentFactory; import dr.app.beauti.components.tipdatesampling.TipDateSamplingComponentFactory; import dr.app.beauti.datapanel.DataPanel; import dr.app.beauti.generator.BeastGenerator; import dr.app.beauti.generator.Generator; import dr.app.beauti.mcmcpanel.MCMCPanel; import dr.app.beauti.operatorspanel.OperatorsPanel; import dr.app.beauti.options.BeautiOptions; import dr.app.beauti.options.PartitionTreePrior; import dr.app.beauti.options.STARBEASTOptions; import dr.app.beauti.options.TraitData; import dr.app.beauti.priorsPanel.DefaultPriorTableDialog; import dr.app.beauti.priorsPanel.PriorsPanel; import dr.app.beauti.siteModelsPanel.SiteModelsPanel; import dr.app.beauti.taxonsetspanel.SpeciesSetPanel; import dr.app.beauti.taxonsetspanel.TaxonSetPanel; import dr.app.beauti.tipdatepanel.TipDatesPanel; import dr.app.beauti.traitspanel.TraitsPanel; import dr.app.beauti.treespanel.TreesPanel; import dr.app.beauti.util.BEAUTiImporter; import dr.app.beauti.util.TextUtil; import dr.app.gui.FileDrop; import dr.app.util.OSType; import dr.app.util.Utils; import dr.evolution.io.Importer.ImportException; import dr.evolution.io.NexusImporter.MissingBlockException; import jam.framework.DocumentFrame; import jam.framework.Exportable; import jam.util.IconUtils; import org.jdom.JDOMException; import javax.swing.*; import javax.swing.border.Border; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.plaf.BorderUIResource; import java.awt.*; import java.awt.event.HierarchyBoundsListener; import java.awt.event.HierarchyEvent; import java.io.*; import java.util.HashMap; import java.util.Map; /** * @author Andrew Rambaut * @author Alexei Drummond * @version $Id: BeautiFrame.java,v 1.22 2006/09/09 16:07:06 rambaut Exp $ */ public class BeautiFrame extends DocumentFrame { private static final long serialVersionUID = 2114148696789612509L; public final static String DATA_PARTITIONS = "Partitions"; public final static String TAXON_SETS = "Taxa"; public final static String TIP_DATES = "Tips"; public final static String TRAITS = "Traits"; public final static String SITE_MODELS = "Sites"; public final static String CLOCK_MODELS = "Clocks"; public final static String TREES = "Trees"; public final static String ANCESTRAL_STATES = "States"; public final static String PRIORS = "Priors"; public final static String OPERATORS = "Operators"; public final static String MCMC = "MCMC"; private BeautiOptions options; private BeastGenerator generator; private final ComponentFactory[] components; public final JTabbedPane tabbedPane = new JTabbedPane(); public final JLabel statusLabel = new JLabel(); private DataPanel dataPanel; private TipDatesPanel tipDatesPanel; private TraitsPanel traitsPanel; private TaxonSetPanel taxonSetPanel; private SpeciesSetPanel speciesSetPanel; private SiteModelsPanel siteModelsPanel; private AncestralStatesPanel ancestralStatesPanel; private ClockModelsPanel clockModelsPanel; private TreesPanel treesPanel; private PriorsPanel priorsPanel; private OperatorsPanel operatorsPanel; private MCMCPanel mcmcPanel; private BeautiPanel currentPanel; private Map<String, FileDialog> fileDialogs = new HashMap<String, FileDialog>(); private Map<String, JFileChooser> fileChoosers = new HashMap<String, JFileChooser>(); final Icon gearIcon = IconUtils.getIcon(this.getClass(), "images/gear.png"); public BeautiFrame(String title) { super(); setTitle(title); // Prevent the application to close in requestClose() // after a user cancel or a failure in beast file generation setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); // getOpenAction().setEnabled(false); // getSaveAction().setEnabled(false); getFindAction().setEnabled(false); getZoomWindowAction().setEnabled(false); components = new ComponentFactory[] { AncestralStatesComponentFactory.INSTANCE, ContinuousComponentFactory.INSTANCE, DiscreteTraitsComponentFactory.INSTANCE, // DnDsComponentFactory.INSTANCE, DolloComponentFactory.INSTANCE, LinkedParameterComponentFactory.INSTANCE, HierarchicalModelComponentFactory.INSTANCE, MarginalLikelihoodEstimationComponentFactory.INSTANCE, SequenceErrorModelComponentFactory.INSTANCE, TipDateSamplingComponentFactory.INSTANCE }; options = new BeautiOptions(components); generator = new BeastGenerator(options, components); this.getContentPane().addHierarchyBoundsListener(new HierarchyBoundsListener() { public void ancestorMoved(HierarchyEvent e) { } public void ancestorResized(HierarchyEvent e) { setStatusMessage(); } }); } public void initializeComponents() { dataPanel = new DataPanel(this, getImportAction(), getDeleteAction()/*, getImportTraitsAction()*/); tipDatesPanel = new TipDatesPanel(this); traitsPanel = new TraitsPanel(this, dataPanel, getImportTraitsAction()); taxonSetPanel = new TaxonSetPanel(this); speciesSetPanel = new SpeciesSetPanel(this); siteModelsPanel = new SiteModelsPanel(this, getDeleteAction()); ancestralStatesPanel = new AncestralStatesPanel(this); clockModelsPanel = new ClockModelsPanel(this); // clockModelsPanel = new OldClockModelsPanel(this); // oldTreesPanel = new OldTreesPanel(this); treesPanel = new TreesPanel(this, getDeleteAction()); // speciesTreesPanel = new SpeciesTreesPanel(this); priorsPanel = new PriorsPanel(this, false); operatorsPanel = new OperatorsPanel(this); mcmcPanel = new MCMCPanel(this); int index = 0; tabbedPane.addTab(DATA_PARTITIONS, dataPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Import sequence alignments, organize data partitions,<br>" + "link models between partitions and select *BEAST</html>"); tabbedPane.addTab(TAXON_SETS, taxonSetPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Create and edit sets of taxa which can be used to <br>" + "define times of most recent common ancestors and <br>" + "to keep groups monophyletic.</html>"); // tabbedPane.addTab("Species Sets", speciesSetPanel); tabbedPane.addTab(TIP_DATES, tipDatesPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Specify sampling dates of tips for use in temporal <br>" + "analyses of measurably evolving populations.</html>"); tabbedPane.addTab(TRAITS, traitsPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Import and organize continuous and discrete traits <br>" + "for taxa, convert them into data partitions for evolutionary<br>" + "analysis.</html>"); tabbedPane.addTab(SITE_MODELS, siteModelsPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Select evolutionary models to be used for each data <br>" + "partition including substitution models, codon partitioning<br>" + "and trait evolution models.</html>"); tabbedPane.addTab(CLOCK_MODELS, clockModelsPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Select relaxed molecular clock models to be used across <br>" + "the tree. Specify sampling of rates.</html>"); tabbedPane.addTab(TREES, treesPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Select the priors on trees including coalescent models<br>" + "birth-death speciation models and the *BEAST gene tree,<br>" + "species tree options.</html>"); tabbedPane.addTab(ANCESTRAL_STATES, ancestralStatesPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Select options for sampling ancestral states at specific<br>" + "or all common ancestors, models of counting state changes<br>" + "and models of sequencing error for data partitions.</html>"); tabbedPane.addTab(PRIORS, priorsPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Specify prior probability distributions on each and every<br>" + "parameter of the current model.</html>"); tabbedPane.addTab(OPERATORS, operatorsPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Select and adjust the menu of operators that will be used<br>" + "to propose changes to the parameters. Switch off operators<br>" + "on certain parameters to fix them to initial values.</html>"); tabbedPane.addTab(MCMC, mcmcPanel); tabbedPane.setToolTipTextAt(index++, "<html>" + "Specify the details of MCMC sampling. This includes chain<br>" + "length, sampling frequencies, log file names and more.</html>"); for (int i = 1; i < tabbedPane.getTabCount(); i++) { tabbedPane.setEnabledAt(i, false); } currentPanel = (BeautiPanel) tabbedPane.getSelectedComponent(); tabbedPane.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { BeautiPanel selectedPanel = (BeautiPanel) tabbedPane.getSelectedComponent(); if (selectedPanel == dataPanel) { dataPanel.selectionChanged(); } else { getDeleteAction().setEnabled(false); } currentPanel.getOptions(options); setAllOptions(); currentPanel = selectedPanel; } }); JPanel basePanel = new JPanel(new BorderLayout(6, 6)); basePanel.setBorder(new BorderUIResource.EmptyBorderUIResource(new java.awt.Insets(12, 12, 12, 12))); // basePanel.setPreferredSize(new java.awt.Dimension(800, 600)); getExportAction().setEnabled(false); JButton generateButton = new JButton(getExportAction()); generateButton.putClientProperty("JButton.buttonType", "roundRect"); JPanel panel2 = new JPanel(new BorderLayout(6, 6)); panel2.add(statusLabel, BorderLayout.WEST); panel2.add(generateButton, BorderLayout.EAST); panel2.setMinimumSize(new java.awt.Dimension(10, 10)); basePanel.add(tabbedPane, BorderLayout.CENTER); basePanel.add(panel2, BorderLayout.SOUTH); add(basePanel, BorderLayout.CENTER); Toolkit tk = Toolkit.getDefaultToolkit(); Dimension d = tk.getScreenSize(); // System.out.println("Screen width = " + d.width); // System.out.println("Screen height = " + d.height); if (d.width < 1000 || d.height < 700) { setSize(new java.awt.Dimension(700, 550)); } else { setSize(new java.awt.Dimension(1024, 768)); } if (OSType.isMac()) { setMinimumSize(new java.awt.Dimension(640, 480)); } setAllOptions(); Color focusColor = UIManager.getColor("Focus.color"); Border focusBorder = BorderFactory.createMatteBorder(2, 2, 2, 2, focusColor); dataPanel.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); new FileDrop(null, dataPanel, focusBorder, new FileDrop.Listener() { public void filesDropped(java.io.File[] files) { importFiles(files); } // end filesDropped }); // end FileDrop.Listener } /** * set all the options for all panels */ public void setAllOptions() { try { dataPanel.setOptions(options); tipDatesPanel.setOptions(options); traitsPanel.setOptions(options); if (options.useStarBEAST) { speciesSetPanel.setOptions(options); } else { taxonSetPanel.setOptions(options); } siteModelsPanel.setOptions(options); clockModelsPanel.setOptions(options); treesPanel.setOptions(options); ancestralStatesPanel.setOptions(options); priorsPanel.setOptions(options); operatorsPanel.setOptions(options); mcmcPanel.setOptions(options); setStatusMessage(); } catch (IllegalArgumentException iae) { iae.printStackTrace(System.err); JOptionPane.showMessageDialog(this, iae.getMessage(), "Illegal Argument Exception", JOptionPane.ERROR_MESSAGE); } // enable/disable the other tabs and generate option depending on whether any // data has been loaded. boolean enabled = options.getDataPartitions().size() > 0; for (int i = 1; i < tabbedPane.getTabCount(); i++) { tabbedPane.setEnabledAt(i, enabled); } getExportAction().setEnabled(enabled); } /** * get all the options for all panels */ private void getAllOptions() { try { dataPanel.getOptions(options); tipDatesPanel.getOptions(options); traitsPanel.getOptions(options); if (options.useStarBEAST) { speciesSetPanel.getOptions(options); } else { taxonSetPanel.getOptions(options); } siteModelsPanel.getOptions(options); clockModelsPanel.getOptions(options); treesPanel.getOptions(options); ancestralStatesPanel.getOptions(options); priorsPanel.getOptions(options); operatorsPanel.getOptions(options); mcmcPanel.getOptions(options); } catch (IllegalArgumentException iae) { iae.printStackTrace(System.err); JOptionPane.showMessageDialog(this, iae.getMessage(), "Illegal Argument Exception", JOptionPane.ERROR_MESSAGE); } } public void doSelectAll() { if (currentPanel == dataPanel) { dataPanel.selectAll(); } } public final void dataSelectionChanged(boolean isSelected) { getDeleteAction().setEnabled(isSelected); } public final void modelSelectionChanged(boolean isSelected) { getDeleteAction().setEnabled(isSelected); } public void doDelete() { if (tabbedPane.getSelectedComponent() == dataPanel) { dataPanel.removeSelection(); // } else if (tabbedPane.getSelectedComponent() == modelsPanel) { // modelsPanel.delete(); // } else if (tabbedPane.getSelectedComponent() == treesPanel) { // treesPanel.delete(); } else { throw new RuntimeException("Delete should only be accessable from the Data and Models panels"); } setStatusMessage(); } public boolean requestClose() { if (isDirty() && options.hasData() && isVisible()) { int option = JOptionPane.showConfirmDialog(this, "You have made changes but have not generated\n" + "a BEAST XML file. Do you wish to generate\n" + "before closing this window?", "Unused changes", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); if (option == JOptionPane.YES_OPTION) { return doGenerate(); } else if (option == JOptionPane.CANCEL_OPTION || option == JOptionPane.DEFAULT_OPTION) { return false; } return true; } return true; } public void doApplyTemplate() { FileDialog dialog = new FileDialog(this, "Apply Template", FileDialog.LOAD); dialog.setVisible(true); if (dialog.getFile() != null) { File file = new File(dialog.getDirectory(), dialog.getFile()); try { readFromFile(file); } catch (FileNotFoundException fnfe) { JOptionPane.showMessageDialog(this, "Unable to open template file: File not found", "Unable to open file", JOptionPane.ERROR_MESSAGE); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Unable to read template file: " + ioe.getMessage(), "Unable to read file", JOptionPane.ERROR_MESSAGE); } } } protected boolean readFromFile(File file) throws IOException { FileInputStream fileIn = new FileInputStream(file); try { ObjectInputStream in = new ObjectInputStream(fileIn); options = (BeautiOptions) in.readObject(); in.close(); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Unable to read BEAUti file. BEAUti can only read files\n" + "created by 'Saving' within BEAUti. It cannot read BEAST\n" + "XML files. To read data within BEAST XML files, use\n" + "the 'Import' option.", "Unable to read file", JOptionPane.ERROR_MESSAGE); } catch (ClassNotFoundException cnfe) { JOptionPane.showMessageDialog(this, "Unable to read BEAUti file: " + cnfe.getMessage(), "Unable to read file", JOptionPane.ERROR_MESSAGE); cnfe.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. return false; } fileIn.close(); options.registerComponents(components); generator = new BeastGenerator(options, components); return true; } public String getDefaultFileName() { return options.fileNameStem + ".beauti"; } protected boolean writeToFile(File file) throws IOException { OutputStream fileOut = new FileOutputStream(file); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(options); out.close(); fileOut.close(); return true; } public final void doImport() { File[] files = selectImportFiles("Import Aligment...", true, new FileNameExtensionFilter[] { new FileNameExtensionFilter( "Microsatellite (tab-delimited *.txt) Files", "txt"), new FileNameExtensionFilter( "NEXUS, BEAST or FASTA Files", "nex", "nexus", "nx", "xml", "beast", "fa", "fasta", "afa")}); // new FileNameExtensionFilter( "Microsatellite (tab-delimited *.txt) Files", "txt"); if (files != null && files.length != 0) { importFiles(files); tabbedPane.setSelectedComponent(dataPanel); } } private void importFiles(File[] files) { for (File file : files) { if (file == null || file.getName().equals("")) { JOptionPane.showMessageDialog(this, "Invalid file name", "Invalid file name", JOptionPane.ERROR_MESSAGE); } else { try { BEAUTiImporter beautiImporter = new BEAUTiImporter(this, options); beautiImporter.importFromFile(file); setDirty(); // } catch (FileNotFoundException fnfe) { // JOptionPane.showMessageDialog(this, "Unable to open file: File not found", // "Unable to open file", JOptionPane.ERROR_MESSAGE); } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "File I/O Error unable to read file: " + ioe.getMessage(), "Unable to read file", JOptionPane.ERROR_MESSAGE); ioe.printStackTrace(); // there may be other files in the list so don't return // return; } catch (MissingBlockException ex) { JOptionPane.showMessageDialog(this, "TAXON, DATA or CHARACTERS block is missing in Nexus file: " + ex, "Missing Block in Nexus File", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); } catch (ImportException ime) { JOptionPane.showMessageDialog(this, "Error parsing imported file: " + ime, "Error reading file", JOptionPane.ERROR_MESSAGE); ime.printStackTrace(); } catch (JDOMException jde) { JOptionPane.showMessageDialog(this, "Error parsing imported file: " + jde, "Error reading file", JOptionPane.ERROR_MESSAGE); jde.printStackTrace(); } } } if (!options.hasIdenticalTaxa()) { setAllOptions(); // need this to refresh panels otherwise it will throw exception dataPanel.selectAll(); dataPanel.unlinkTrees(); } setAllOptions(); } public final boolean doImportTraits() { if (options.taxonList != null) { // validation of check empty taxonList File[] files = selectImportFiles("Import Traits File...", false, new FileNameExtensionFilter[] { new FileNameExtensionFilter("Tab-delimited text files", "txt", "tab", "dat") }); if (files != null && files.length != 0) { try { BEAUTiImporter beautiImporter = new BEAUTiImporter(this, options); beautiImporter.importTraits(files[0]); } catch (FileNotFoundException fnfe) { JOptionPane.showMessageDialog(this, "Unable to open file: File not found", "Unable to open file", JOptionPane.ERROR_MESSAGE); return false; } catch (IOException ioe) { JOptionPane.showMessageDialog(this, "Unable to read file: " + ioe.getMessage(), "Unable to read file", JOptionPane.ERROR_MESSAGE); return false; } catch (Exception ex) { ex.printStackTrace(System.err); JOptionPane.showMessageDialog(this, "Fatal exception: " + ex, "Error reading file", JOptionPane.ERROR_MESSAGE); ex.printStackTrace(); return false; } } else { return false; } traitsPanel.fireTraitsChanged(); setAllOptions(); tabbedPane.setSelectedComponent(traitsPanel); return true; } else { JOptionPane.showMessageDialog(this, "No taxa loaded yet, please import Alignment file.", "No taxa loaded", JOptionPane.ERROR_MESSAGE); return false; } } public boolean validateTraitName(String traitName) { // check that the name is valid if (traitName.trim().length() == 0) { Toolkit.getDefaultToolkit().beep(); return false; } // disallow a trait called 'date' if (traitName.equalsIgnoreCase("date")) { JOptionPane.showMessageDialog(this, "This trait name has a special meaning. Use the 'Tip Date' panel\n" + " to set dates for taxa.", "Reserved trait name", JOptionPane.WARNING_MESSAGE); return false; } if (options.useStarBEAST && traitName.equalsIgnoreCase(TraitData.TRAIT_SPECIES)) { JOptionPane.showMessageDialog(this, "This trait name is already in used to denote species\n" + "for *BEAST. Please select a different name.", "Reserved trait name", JOptionPane.WARNING_MESSAGE); return false; } // check that the trait name doesn't exist if (options.traitExists(traitName)) { int option = JOptionPane.showConfirmDialog(this, "A trait of this name already exists. Do you wish to replace\n" + "it with this new trait? This may result in the loss or change\n" + "in trait values for the taxa.", "Overwrite trait?", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (option == JOptionPane.NO_OPTION) { return false; } } return true; } /** * Attempts to set up starBEAST - returns true if successful * @param useStarBEAST * @return */ public boolean setupStarBEAST(boolean useStarBEAST) { if (useStarBEAST) { if (!options.traitExists(TraitData.TRAIT_SPECIES)) { if (!traitsPanel.addTrait( "<html><p>" + "StarBEAST requires a trait to give species designations<br>" + "for each taxon. Create or import a discrete trait<br>" + "labelled 'species'.</p></html>", TraitData.TRAIT_SPECIES, true /* isSpeciesTrait */ )) { return false; } } else if (options.getTraitPartitions(options.getTrait(TraitData.TRAIT_SPECIES)).size() > 0) { int option = JOptionPane.showConfirmDialog(this, "The trait named '" + TraitData.TRAIT_SPECIES + "', used to denote species in *BEAST, is\n" + "already in use as a data partition. Do you wish to continue?", "Species trait already in use", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); if (option == JOptionPane.NO_OPTION) { return false; } } dataPanel.selectAll(); dataPanel.unlinkAll(); options.starBEASTOptions = new STARBEASTOptions(options); options.fileNameStem = "StarBEASTLog"; tabbedPane.removeTabAt(1); tabbedPane.insertTab("Species Sets", null, speciesSetPanel, null, 1); } else { // remove species options.fileNameStem = MCMCPanel.DEFAULT_FILE_NAME_STEM; tabbedPane.removeTabAt(1); tabbedPane.insertTab("Taxon Sets", null, taxonSetPanel, null, 1); } options.useStarBEAST = useStarBEAST; treesPanel.updatePriorPanelForSpeciesAnalysis(); setStatusMessage(); return true; } public void updateDiscreteTraitAnalysis() { setStatusMessage(); } public void setupEBSP() { dataPanel.selectAll(); dataPanel.unlinkAll(); setAllOptions(); } public PartitionTreePrior getCurrentPartitionTreePrior() { treesPanel.setOptions(options); // need this to refresh the currentTreeModel return treesPanel.currentTreeModel.getPartitionTreePrior(); } public void setStatusMessage() { int width = this.getWidth() - 260; // minus generate button size if (width < 100) width = 100; // prevent too narrow String tw = TextUtil.wrapText(options.statusMessage(), statusLabel, width); // System.out.println(this.getWidth() + " " + tw); statusLabel.setText(tw); } public final boolean doGenerate() { try { generator.checkOptions(); } catch (Generator.GeneratorException ge) { ge.printStackTrace(System.err); JOptionPane.showMessageDialog(this, ge.getMessage(), "Invalid BEAUti setting : ", JOptionPane.ERROR_MESSAGE); if (ge.getSwitchToPanel() != null) { switchToPanel(ge.getSwitchToPanel()); } return false; } DefaultPriorTableDialog defaultPriorDialog = new DefaultPriorTableDialog(this); if (!defaultPriorDialog.showDialog(options)) { return false; } File file = selectExportFile("Generate BEAST XML File...", new FileNameExtensionFilter("BEAST XML File", "xml", "beast")); if (file != null) { try { getAllOptions(); generator.generateXML(file); } catch (IOException ioe) { ioe.printStackTrace(System.err); JOptionPane.showMessageDialog(this, "Unable to generate file due to I/O issue: " + ioe.getMessage(), "Unable to generate file", JOptionPane.ERROR_MESSAGE); return false; } catch (Generator.GeneratorException e) { e.printStackTrace(System.err); JOptionPane.showMessageDialog(this, "The BEAST XML is incomplete because :\n" + e.getMessage(), "The BEAST XML is incomplete", JOptionPane.ERROR_MESSAGE); return false; } catch (Exception e) { e.printStackTrace(System.err); JOptionPane.showMessageDialog(this, "Unable to generate file: " + e.getMessage(), "Unable to generate file", JOptionPane.ERROR_MESSAGE); return false; } clearDirty(); return true; } return false; } /** * Use the native file dialog on the Mac because the Swing one is bad. On linux, the native * one is bad. No preference on Windows. * @param title * @return */ public File[] selectImportFiles(final String title, boolean multipleSelection, FileNameExtensionFilter[] fileNameExtensionFilters) { if (Boolean.parseBoolean(System.getProperty("use.native.choosers", Boolean.toString(OSType.isMac())))) { FileDialog importDialog = fileDialogs.get(title); if (importDialog == null) { importDialog = new FileDialog(this, title, FileDialog.LOAD); fileDialogs.put(title, importDialog); } importDialog.setVisible(true); if (importDialog.getFile() != null) { return new File[] { new File(importDialog.getDirectory(), importDialog.getFile()) }; } } else { JFileChooser importChooser = fileChoosers.get(title); if (importChooser == null) { importChooser = new JFileChooser(Utils.getCWD()); importChooser.setMultiSelectionEnabled(multipleSelection); for (FileNameExtensionFilter fileNameExtensionFilter : fileNameExtensionFilters) { importChooser.setFileFilter(fileNameExtensionFilter); } importChooser.setDialogTitle(title); fileChoosers.put(title, importChooser); } int returnVal = importChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { if (importChooser.isMultiSelectionEnabled()) { return importChooser.getSelectedFiles(); } else { return new File[] { importChooser.getSelectedFile() }; } } } return null; } /** * Use the native file dialog on the Mac because the Swing one is bad. On linux, the native * one is bad. No preference on Windows. * @param title * @return */ private File selectExportFile(final String title, FileNameExtensionFilter fileNameExtensionFilter) { if (Boolean.parseBoolean(System.getProperty("use.native.choosers", Boolean.toString(OSType.isMac())))) { FileDialog exportDialog = fileDialogs.get(title); if (exportDialog == null) { exportDialog = new FileDialog(this, title, FileDialog.SAVE); fileDialogs.put(title, exportDialog); } exportDialog.setFile(options.fileNameStem + ".xml"); exportDialog.setVisible(true); // Mac dialog box will already have asked about overwriting file... if (exportDialog.getFile() != null) { return new File(exportDialog.getDirectory(), exportDialog.getFile()); } } else { JFileChooser exportChooser = fileChoosers.get(title); if (exportChooser == null) { exportChooser = new JFileChooser(Utils.getCWD()); // make JFileChooser chooser remember previous path exportChooser = new JFileChooser(Utils.getCWD()); exportChooser.setFileFilter(fileNameExtensionFilter); exportChooser.setDialogTitle(title); fileChoosers.put(title, exportChooser); } // offer stem as default exportChooser.setSelectedFile(new File(options.fileNameStem + ".xml")); final int returnVal = exportChooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File file = exportChooser.getSelectedFile(); int n = JOptionPane.YES_OPTION; if (file.exists()) { n = JOptionPane.showConfirmDialog(this, file.getName(), "Overwrite the existing file?", JOptionPane.YES_NO_OPTION); } if (n == JOptionPane.YES_OPTION) { return file; } } } return null; } public void switchToPanel(String panelName) { for (int i = 0; i < tabbedPane.getTabCount(); i++) { if (tabbedPane.getTitleAt(i).equals(panelName)) { tabbedPane.setSelectedIndex(i); break; } } } public JComponent getExportableComponent() { JComponent exportable = null; Component comp = tabbedPane.getSelectedComponent(); if (comp instanceof Exportable) { exportable = ((Exportable) comp).getExportableComponent(); } else if (comp instanceof JComponent) { exportable = (JComponent) comp; } return exportable; } public Action getImportAction() { return importAlignmentAction; } protected AbstractAction importAlignmentAction = new AbstractAction("Import Data...") { private static final long serialVersionUID = 3217702096314745005L; public void actionPerformed(java.awt.event.ActionEvent ae) { doImport(); } }; public Action getImportTraitsAction() { return importTraitsAction; } protected AbstractAction importTraitsAction = new AbstractAction("Import Traits") { private static final long serialVersionUID = 3217702096314745005L; public void actionPerformed(java.awt.event.ActionEvent ae) { doImportTraits(); } }; public Action getExportAction() { return generateAction; } protected AbstractAction generateAction = new AbstractAction("Generate BEAST File...", gearIcon) { private static final long serialVersionUID = -5329102618630268783L; public void actionPerformed(java.awt.event.ActionEvent ae) { doGenerate(); } }; }