/* * DataPanel.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 */ package dr.app.beauti.datapanel; import dr.app.beauti.BeautiFrame; import dr.app.beauti.BeautiPanel; import dr.app.beauti.ComboBoxRenderer; import dr.app.beauti.alignmentviewer.AlignmentViewer; import dr.app.beauti.alignmentviewer.AminoAcidDecorator; import dr.app.beauti.alignmentviewer.NucleotideDecorator; import dr.app.beauti.alignmentviewer.StateCellDecorator; import dr.app.beauti.options.*; import dr.app.beauti.util.PanelUtils; import dr.app.gui.table.TableEditorStopper; import dr.evolution.alignment.Alignment; import dr.evolution.datatype.DataType; import dr.evolution.datatype.Microsatellite; import dr.evolution.util.Taxa; import jam.framework.Exportable; import jam.panels.ActionPanel; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.plaf.BorderUIResource; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * @author Andrew Rambaut * @author Alexei Drummond * @version $Id: DataPanel.java,v 1.17 2006/09/05 13:29:34 rambaut Exp $ */ public class DataPanel extends BeautiPanel implements Exportable { JScrollPane scrollPane = new JScrollPane(); JTable dataTable = null; DataTableModel dataTableModel = null; UnlinkModelsAction unlinkModelsAction = new UnlinkModelsAction(); LinkModelsAction linkModelsAction = new LinkModelsAction(); UnlinkClocksAction unlinkClocksAction = new UnlinkClocksAction(); LinkClocksAction linkClocksAction = new LinkClocksAction(); UnlinkTreesAction unlinkTreesAction = new UnlinkTreesAction(); LinkTreesAction linkTreesAction = new LinkTreesAction(); CreateTraitPartitionAction createTraitPartitionAction = new CreateTraitPartitionAction(); ViewPartitionAction viewPartitionAction = new ViewPartitionAction(); // ShowAction showAction = new ShowAction(); public JCheckBox useStarBEASTCheck = new JCheckBox("Use species tree ancestral reconstruction (*BEAST) Heled & Drummond 2010 "); SelectModelDialog selectModelDialog = null; SelectClockDialog selectClockDialog = null; SelectTreeDialog selectTreeDialog = null; SelectTraitDialog selectTraitDialog = null; BeautiFrame frame = null; BeautiOptions options = null; public DataPanel(BeautiFrame parent, Action importDataAction, Action removeDataAction/*, Action importTraitsAction*/) { this.frame = parent; dataTableModel = new DataTableModel(); dataTable = new JTable(dataTableModel); dataTable.getTableHeader().setReorderingAllowed(false); // dataTable.getTableHeader().setDefaultRenderer( // new HeaderRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); TableColumn col = dataTable.getColumnModel().getColumn(5); ComboBoxRenderer comboBoxRenderer = new ComboBoxRenderer(); comboBoxRenderer.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); col.setCellRenderer(comboBoxRenderer); // col = dataTable.getColumnModel().getColumn(5); // comboBoxRenderer = new ComboBoxRenderer(); // comboBoxRenderer.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); // col.setCellRenderer(comboBoxRenderer); col = dataTable.getColumnModel().getColumn(6); comboBoxRenderer = new ComboBoxRenderer(); comboBoxRenderer.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); col.setCellRenderer(comboBoxRenderer); col = dataTable.getColumnModel().getColumn(7); comboBoxRenderer = new ComboBoxRenderer(); comboBoxRenderer.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); col.setCellRenderer(comboBoxRenderer); TableEditorStopper.ensureEditingStopWhenTableLosesFocus(dataTable); dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { selectionChanged(); } }); dataTable.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { showAlignment(); } } }); scrollPane = new JScrollPane(dataTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); scrollPane.setOpaque(false); JToolBar toolBar1 = new JToolBar(); toolBar1.setFloatable(false); toolBar1.setOpaque(false); toolBar1.setLayout(new BoxLayout(toolBar1, BoxLayout.X_AXIS)); JButton button = new JButton(unlinkModelsAction); unlinkModelsAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); button = new JButton(linkModelsAction); linkModelsAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); toolBar1.addSeparator(); button = new JButton(unlinkClocksAction); unlinkClocksAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); button = new JButton(linkClocksAction); linkClocksAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); toolBar1.addSeparator(); button = new JButton(unlinkTreesAction); unlinkTreesAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); button = new JButton(linkTreesAction); linkTreesAction.setEnabled(false); PanelUtils.setupComponent(button); toolBar1.add(button); ActionPanel actionPanel1 = new ActionPanel(false); actionPanel1.setAddAction(importDataAction); actionPanel1.setRemoveAction(removeDataAction); removeDataAction.setEnabled(false); JPanel controlPanel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); controlPanel1.setOpaque(false); controlPanel1.add(actionPanel1); button = new JButton(viewPartitionAction); controlPanel1.add(new JLabel(" ")); viewPartitionAction.setEnabled(false); PanelUtils.setupComponent(button); controlPanel1.add(button); button = new JButton(createTraitPartitionAction); controlPanel1.add(new JLabel(" ")); PanelUtils.setupComponent(button); controlPanel1.add(button); //JPanel panel1 = new JPanel(new BorderLayout()); //panel1.setOpaque(false); //panel1.add(useStarBEASTCheck, BorderLayout.NORTH); //panel1.add(toolBar1, BorderLayout.SOUTH); setOpaque(false); setBorder(new BorderUIResource.EmptyBorderUIResource(new Insets(12, 12, 12, 12))); setLayout(new BorderLayout(0, 0)); add(toolBar1, BorderLayout.NORTH); add(scrollPane, BorderLayout.CENTER); add(controlPanel1, BorderLayout.SOUTH); useStarBEASTCheck.setEnabled(false); useStarBEASTCheck.setToolTipText(STARBEASTOptions.CITATION); useStarBEASTCheck.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(ActionEvent e) { if (!frame.setupStarBEAST(useStarBEASTCheck.isSelected())) { useStarBEASTCheck.setSelected(false); // go back to unchecked } dataTableModel.fireTableDataChanged(); } }); } private void showAlignment() { int[] selRows = dataTable.getSelectedRows(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); Alignment alignment = null; if (partition instanceof PartitionData) alignment = ((PartitionData) partition).getAlignment(); // alignment == null if partition is trait or microsat http://code.google.com/p/beast-mcmc/issues/detail?id=343 if (alignment == null) { JOptionPane.showMessageDialog(this, "Cannot display traits or microsatellite data currently.\nUse the traits panel to view and edit traits.", "Illegal Argument Exception", JOptionPane.ERROR_MESSAGE); return; } JFrame frame = new JFrame(); frame.setSize(800, 600); AlignmentViewer viewer = new AlignmentViewer(); if (alignment.getDataType().getType() == DataType.NUCLEOTIDES) { viewer.setCellDecorator(new StateCellDecorator(new NucleotideDecorator(), false)); } else if (alignment.getDataType().getType() == DataType.AMINO_ACIDS) { viewer.setCellDecorator(new StateCellDecorator(new AminoAcidDecorator(), false)); } else { // no colouring } viewer.setAlignmentBuffer(new BeautiAlignmentBuffer(alignment)); JPanel panel = new JPanel(new BorderLayout()); panel.setOpaque(false); panel.add(viewer, BorderLayout.CENTER); JPanel infoPanel = new JPanel(new BorderLayout()); infoPanel.setOpaque(false); panel.add(infoPanel, BorderLayout.SOUTH); frame.setContentPane(panel); frame.setVisible(true); } } private void fireDataChanged() { options.updatePartitionAllLinks(); frame.setDirty(); } private void modelsChanged() { TableColumn col = dataTable.getColumnModel().getColumn(5); col.setCellEditor(new ComboBoxCellEditor()); col = dataTable.getColumnModel().getColumn(6); col.setCellEditor(new ComboBoxCellEditor()); col = dataTable.getColumnModel().getColumn(7); col.setCellEditor(new DefaultCellEditor(new JComboBox(options.getPartitionTreeModels().toArray()))); } public class ComboBoxCellEditor extends DefaultCellEditor { public ComboBoxCellEditor() { super(new JComboBox()); } public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { ((JComboBox) editorComponent).removeAllItems(); if (column == 5) { for (Object ob : options.getPartitionSubstitutionModels()) { ((JComboBox) editorComponent).addItem(ob); } } else if (column == 6) { for (Object ob : options.getPartitionClockModels()) { ((JComboBox) editorComponent).addItem(ob); } } // if (((JComboBox) editorComponent).contains(value)) // todo need validate whether value in the editorComponent ((JComboBox) editorComponent).setSelectedItem(value); delegate.setValue(value); return editorComponent; } } public void selectionChanged() { int[] selRows = dataTable.getSelectedRows(); boolean hasSelection = (selRows != null && selRows.length != 0); frame.dataSelectionChanged(hasSelection); boolean canUnlink = options.dataPartitions.size() > 1 && hasSelection; boolean canLink = options.dataPartitions.size() > 1 && hasSelection && selRows.length > 1; unlinkModelsAction.setEnabled(canUnlink); linkModelsAction.setEnabled(canLink); unlinkClocksAction.setEnabled(canUnlink); linkClocksAction.setEnabled(canLink); unlinkTreesAction.setEnabled(canUnlink); linkTreesAction.setEnabled(canLink); viewPartitionAction.setEnabled(options.dataPartitions.size() > 1 && hasSelection); } public void setOptions(BeautiOptions options) { this.options = options; modelsChanged(); boolean taxaAvailable = options.taxonList != null && options.taxonList.getTaxonCount() > 0; boolean traitAvailable = options.traits != null && options.traits.size() > 0 && (!options.useStarBEAST); useStarBEASTCheck.setEnabled(taxaAvailable); createTraitPartitionAction.setEnabled(traitAvailable); dataTableModel.fireTableDataChanged(); } public void getOptions(BeautiOptions options) { } public JComponent getExportableComponent() { return dataTable; } public void removeSelection() { int[] selRows = dataTable.getSelectedRows(); Set<AbstractPartitionData> partitionsToRemove = new HashSet<AbstractPartitionData>(); for (int row : selRows) { partitionsToRemove.add(options.dataPartitions.get(row)); } boolean hasIdenticalTaxa = options.hasIdenticalTaxa(); // need to check this before removing partitions // TODO: would probably be a good idea to check if the user wants to remove the last partition options.dataPartitions.removeAll(partitionsToRemove); if (options.dataPartitions.size() == 0) { // all data partitions removed so reset the taxa options.reset(); useStarBEASTCheck.setSelected(false); frame.setupStarBEAST(false); frame.statusLabel.setText(""); frame.setAllOptions(); frame.getExportAction().setEnabled(false); } else if (!hasIdenticalTaxa) { options.updateTaxonList(); } dataTableModel.fireTableDataChanged(); fireDataChanged(); } public void selectAll() { dataTable.selectAll(); } public boolean createFromTraits(List<TraitData> traits) { int selRow = -1; if (selectTraitDialog == null) { selectTraitDialog = new SelectTraitDialog(frame); } if (traits==null || traits.size() == 0) { int result = selectTraitDialog.showDialog(options.traits, null); if (result != JOptionPane.CANCEL_OPTION) { TraitData trait = selectTraitDialog.getTrait(); String name = trait.getName(); if (selectTraitDialog.getMakeCopy()) { name = selectTraitDialog.getName(); } selRow = options.createPartitionForTraits(name, trait); } else { return false; } } else { if (traits.size() > 1) { // a set of traits have been passed to the function int result = selectTraitDialog.showDialog(null, null); if (result != JOptionPane.CANCEL_OPTION) { String name = selectTraitDialog.getName(); selRow = options.createPartitionForTraits(name, traits); } else { return false; } } else { selRow = options.createPartitionForTraits(traits.get(0).getName(), traits); } } modelsChanged(); dataTableModel.fireTableDataChanged(); if (selRow != -1) { dataTable.getSelectionModel().setSelectionInterval(selRow, selRow); } fireDataChanged(); repaint(); return true; } public void unlinkModels() { int[] selRows = dataTable.getSelectedRows(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); PartitionSubstitutionModel model = partition.getPartitionSubstitutionModel(); if (!model.getName().equals(partition.getName())) { PartitionSubstitutionModel newModel = new PartitionSubstitutionModel(options, partition.getName(), model); partition.setPartitionSubstitutionModel(newModel); } } modelsChanged(); fireDataChanged(); repaint(); } public void linkModels() { int[] selRows = dataTable.getSelectedRows(); List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>(); DataType dateType = null; for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); if (dateType == null) { dateType = partition.getDataType(); } else { if (partition.getDataType() != dateType) { JOptionPane.showMessageDialog(this, "Can only link the models for data partitions \n" + "of the same data type (e.g., nucleotides)", "Unable to link models", JOptionPane.ERROR_MESSAGE); return; } } if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition); } Object[] modelArray = options.getPartitionSubstitutionModels(selectedPartitionData).toArray(); if (selectModelDialog == null) { selectModelDialog = new SelectModelDialog(frame); } int result = selectModelDialog.showDialog(modelArray); if (result != JOptionPane.CANCEL_OPTION) { PartitionSubstitutionModel model = selectModelDialog.getModel(); if (selectModelDialog.getMakeCopy()) { model.setName(selectModelDialog.getName()); } for (AbstractPartitionData partition : selectedPartitionData) { partition.setPartitionSubstitutionModel(model); } } if (options.getPartitionSubstitutionModels(Microsatellite.INSTANCE).size() <= 1) { options.shareMicroSat = true; } modelsChanged(); fireDataChanged(); repaint(); } public void unlinkClocks() { // reuse previous PartitionTreePrior int[] selRows = dataTable.getSelectedRows(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); PartitionClockModel model = partition.getPartitionClockModel(); if (!model.getName().equals(partition.getName())) { PartitionClockModel newModel = new PartitionClockModel(options, partition.getName(), model); partition.setPartitionClockModel(newModel); } } modelsChanged(); fireDataChanged(); repaint(); } public void linkClocks() { // keep previous PartitionTreePrior for reuse int[] selRows = dataTable.getSelectedRows(); List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition); } Object[] modelArray = options.getPartitionClockModels(selectedPartitionData).toArray(); if (selectClockDialog == null) { selectClockDialog = new SelectClockDialog(frame); } int result = selectClockDialog.showDialog(modelArray); if (result != JOptionPane.CANCEL_OPTION) { PartitionClockModel model = selectClockDialog.getModel(); if (selectClockDialog.getMakeCopy()) { model.setName(selectClockDialog.getName()); } for (AbstractPartitionData partition : selectedPartitionData) { partition.setPartitionClockModel(model); } } modelsChanged(); fireDataChanged(); repaint(); } public void unlinkTrees() { // reuse previous PartitionTreePrior int[] selRows = dataTable.getSelectedRows(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); PartitionTreeModel model = partition.getPartitionTreeModel(); if (!model.getName().equals(partition.getName()) && partition.getTraits() == null) {// not a trait PartitionTreeModel newTree = new PartitionTreeModel(options, partition.getName(), model); // this prevents partition not broken, and used for unsharing tree prior only, // because sharing uses shareSameTreePrior, unsharing uses getPartitionTreePrior // newTree.setPartitionTreePrior(newPrior); // important partition.setPartitionTreeModel(newTree); } } options.linkTreePriors(frame.getCurrentPartitionTreePrior()); modelsChanged(); fireDataChanged(); repaint(); } public void linkTrees() { // keep previous PartitionTreePrior for reuse int[] selRows = dataTable.getSelectedRows(); List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>(); for (int row : selRows) { AbstractPartitionData partition = options.dataPartitions.get(row); if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition); } if (selectedPartitionData.size() > 1) { if (!options.hasIdenticalTaxa(selectedPartitionData)) { String errMsg = "To share a tree, partitions need to have identical taxa."; if (selectedPartitionData.get(0).getDataType().getType() == DataType.MICRO_SAT) errMsg += "\nThe data must be all diploid or all haploid when you want to link the tree."; JOptionPane.showMessageDialog(this, errMsg, "Illegal Configuration", JOptionPane.ERROR_MESSAGE); return; } } Object[] treeArray = options.getPartitionTreeModels(selectedPartitionData).toArray(); if (selectTreeDialog == null) { selectTreeDialog = new SelectTreeDialog(frame); } int result = selectTreeDialog.showDialog(treeArray); if (result != JOptionPane.CANCEL_OPTION) { PartitionTreeModel model = selectTreeDialog.getTree(); if (selectTreeDialog.getMakeCopy()) { model.setName(selectTreeDialog.getName()); } PartitionTreePrior prior = model.getPartitionTreePrior(); options.linkTreePriors(prior); for (AbstractPartitionData partition : selectedPartitionData) { partition.setPartitionTreeModel(model); } for (Taxa taxa : options.taxonSets) { // Issue 454: all the taxon sets are deleted when link/unlink tree PartitionTreeModel prevModel = options.taxonSetsTreeModel.get(taxa); if (prevModel != model) options.taxonSetsTreeModel.put(taxa, model); } } modelsChanged(); fireDataChanged(); repaint(); } public void unlinkAll() { unlinkModels(); unlinkClocks(); unlinkTrees(); } class DataTableModel extends AbstractTableModel { private static final long serialVersionUID = -6707994233020715574L; String[] columnNames = {"Partition Name", "File Name", "Taxa", "Sites", "Data Type", "Site Model", "Clock Model", "Partition Tree"}; public DataTableModel() { } public int getColumnCount() { return columnNames.length; } public int getRowCount() { if (options == null) return 0; // return options.getPartitionDataNoSpecies().size(); return options.dataPartitions.size(); } public Object getValueAt(int row, int col) { // PartitionData partition = options.getPartitionDataNoSpecies().get(row); AbstractPartitionData partition = options.dataPartitions.get(row); switch (col) { case 0: return partition.getName(); case 1: return partition.getFileName(); case 2: return "" + (partition.getTaxonCount() >= 0 ? partition.getTaxonCount() : "-"); case 3: return "" + (partition.getSiteCount() >= 0 ? partition.getSiteCount() : "-"); case 4: return partition.getDataDescription(); case 5: // return partition.getPloidyType(); // case 6: return partition.getPartitionSubstitutionModel().getName(); case 6: return "" + (partition.getPartitionClockModel() != null ? partition.getPartitionClockModel().getName() : "-"); case 7: return partition.getPartitionTreeModel().getName(); default: throw new IllegalArgumentException("unknown column, " + col); } } public void setValueAt(Object aValue, int row, int col) { AbstractPartitionData partition = options.dataPartitions.get(row); switch (col) { case 0: String name = ((String) aValue).trim(); if (options.hasPartitionData(name)) { JOptionPane.showMessageDialog(frame, "Duplicate partition name.", "Illegal Argument Exception", JOptionPane.ERROR_MESSAGE); return; } if (name.length() > 0) { options.renamePartition(partition, name); } break; case 5: // partition.setPloidyType((PloidyType) aValue); // break; // case 6: if (((PartitionSubstitutionModel) aValue).getDataType().equals(partition.getDataType())) { partition.setPartitionSubstitutionModel((PartitionSubstitutionModel) aValue); } break; case 6: partition.setPartitionClockModel((PartitionClockModel) aValue); break; case 7: partition.setPartitionTreeModel((PartitionTreeModel) aValue); break; } fireDataChanged(); } public boolean isCellEditable(int row, int col) { boolean editable; AbstractPartitionData partition = options.dataPartitions.get(row); switch (col) { case 0:// name editable = true; break; // case 5:// ploidy type selection menu // editable = true; // break; case 5:// substitution model selection menu editable = partition.getDataType().getType() != DataType.CONTINUOUS; break; case 6:// clock model selection menu editable = partition.getDataType().getType() != DataType.CONTINUOUS; break; case 7:// tree selection menu editable = true; break; default: editable = false; } return editable; } public String getColumnName(int column) { return columnNames[column]; } public Class getColumnClass(int c) { if (getRowCount() == 0) { return Object.class; } return getValueAt(0, c).getClass(); } public String toString() { StringBuffer buffer = new StringBuffer(); buffer.append(getColumnName(0)); for (int j = 1; j < getColumnCount(); j++) { buffer.append("\t"); buffer.append(getColumnName(j)); } buffer.append("\n"); for (int i = 0; i < getRowCount(); i++) { buffer.append(getValueAt(i, 0)); for (int j = 1; j < getColumnCount(); j++) { buffer.append("\t"); buffer.append(getValueAt(i, j)); } buffer.append("\n"); } return buffer.toString(); } } public class UnlinkModelsAction extends AbstractAction { public UnlinkModelsAction() { super("Unlink Subst. Models"); setToolTipText("Use this tool to use a different substitution model for each selected data partition"); } public void actionPerformed(ActionEvent ae) { unlinkModels(); } } public class LinkModelsAction extends AbstractAction { public LinkModelsAction() { super("Link Subst. Models"); setToolTipText("Use this tool to set all the selected partitions to the same substitution model"); } public void actionPerformed(ActionEvent ae) { linkModels(); } } public class UnlinkClocksAction extends AbstractAction { public UnlinkClocksAction() { super("Unlink Clock Models"); setToolTipText("Use this tool to use a different clock model for each selected data partition"); } public void actionPerformed(ActionEvent ae) { unlinkClocks(); } } public class LinkClocksAction extends AbstractAction { public LinkClocksAction() { super("Link Clock Models"); setToolTipText("Use this tool to set all the selected partitions to the same clock model"); } public void actionPerformed(ActionEvent ae) { linkClocks(); } } public class UnlinkTreesAction extends AbstractAction { public UnlinkTreesAction() { super("Unlink Trees"); setToolTipText("Use this tool to use a different tree for each selected data partition"); } public void actionPerformed(ActionEvent ae) { unlinkTrees(); } } public class LinkTreesAction extends AbstractAction { public LinkTreesAction() { super("Link Trees"); setToolTipText("Use this tool to set all the selected partitions to the same tree"); } public void actionPerformed(ActionEvent ae) { linkTrees(); } } public class ViewPartitionAction extends AbstractAction { public ViewPartitionAction() { super("View Partition ..."); setToolTipText("View alignment in a window."); } public void actionPerformed(ActionEvent ae) { showAlignment(); } } public class CreateTraitPartitionAction extends AbstractAction { public CreateTraitPartitionAction() { super("Create partition from trait ..."); setToolTipText("Create a data partition from a trait. Traits can be defined in the Traits panel."); } public void actionPerformed(ActionEvent ae) { createFromTraits(null); } } // public class ShowAction extends AbstractAction { // public ShowAction() { // super("Show"); // setToolTipText("Display the selected alignments"); // } // // public void actionPerformed(ActionEvent ae) { // showAlignment(); // } // } // public class UnlinkAllAction extends AbstractAction { // public UnlinkAllAction() { // super("Unlink All"); // setToolTipText("Use this tool to use a different substitution model, different clock model and different tree for each selected data partition"); // } // // public void actionPerformed(ActionEvent ae) { // unlinkAll(); // } // } // // public class LinkAllAction extends AbstractAction { // public LinkAllAction() { // super("Link All"); // setToolTipText("Use this tool to set all the selected partitions to the same substitution, clock model and tree"); // } // // public void actionPerformed(ActionEvent ae) { // linkAll(); // } // } }