/* * SiteModelsPanel.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.siteModelsPanel; import dr.app.beauti.BeautiFrame; import dr.app.beauti.BeautiPanel; import dr.app.beauti.components.sequenceerror.SequenceErrorModelComponentOptions; import dr.app.beauti.options.AbstractPartitionData; import dr.app.beauti.options.BeautiOptions; import dr.app.beauti.options.PartitionSubstitutionModel; import dr.app.beauti.types.SequenceErrorType; import dr.app.beauti.util.PanelUtils; import dr.app.gui.table.TableEditorStopper; import dr.evolution.datatype.DataType; import jam.framework.Exportable; import jam.panels.OptionsPanel; import jam.table.TableRenderer; import javax.swing.*; import javax.swing.border.TitledBorder; 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 javax.swing.table.TableColumnModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.*; import java.util.List; import java.util.logging.Logger; /** * @author Andrew Rambaut * @author Alexei Drummond * @version $Id: ModelPanel.java,v 1.17 2006/09/05 13:29:34 rambaut Exp $ */ public class SiteModelsPanel extends BeautiPanel implements Exportable { public final static boolean DEBUG = false; private static final long serialVersionUID = 2778103564318492601L; private static final int MINIMUM_TABLE_WIDTH = 140; private JTable modelTable = null; private ModelTableModel modelTableModel = null; private BeautiOptions options = null; private JPanel modelPanelParent; private PartitionSubstitutionModel currentModel = null; private Map<PartitionSubstitutionModel, PartitionModelPanel> modelPanels = new HashMap<PartitionSubstitutionModel, PartitionModelPanel>(); private TitledBorder modelBorder; private CloneModelDialog cloneModelDialog = null; BeautiFrame frame = null; // CreateModelDialog createModelDialog = null; boolean settingOptions = false; CloneModelsAction cloneModelsAction = new CloneModelsAction(); public SiteModelsPanel(BeautiFrame parent, Action removeModelAction) { super(); this.frame = parent; modelTableModel = new ModelTableModel(); modelTable = new JTable(modelTableModel); modelTable.getTableHeader().setReorderingAllowed(false); modelTable.getTableHeader().setResizingAllowed(false); // modelTable.getTableHeader().setDefaultRenderer( // new HeaderRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); final TableColumnModel model = modelTable.getColumnModel(); final TableColumn tableColumn0 = model.getColumn(0); tableColumn0.setCellRenderer(new ModelsTableCellRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); TableEditorStopper.ensureEditingStopWhenTableLosesFocus(modelTable); modelTable.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); modelTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { selectionChanged(); } }); JScrollPane scrollPane = new JScrollPane(modelTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setOpaque(false); // ActionPanel actionPanel1 = new ActionPanel(false); // actionPanel1.setAddAction(addModelAction); // actionPanel1.setRemoveAction(removeModelAction); JPanel controlPanel1 = new JPanel(new FlowLayout(FlowLayout.LEFT)); controlPanel1.setOpaque(false); // controlPanel1.add(actionPanel1); JPanel panel = new JPanel(new BorderLayout(0, 0)); panel.setOpaque(false); panel.add(scrollPane, BorderLayout.CENTER); // panel.add(controlPanel1, BorderLayout.SOUTH); panel.setMinimumSize(new Dimension(MINIMUM_TABLE_WIDTH, 0)); JToolBar toolBar = new JToolBar(); toolBar.setFloatable(false); toolBar.setOpaque(false); toolBar.setLayout(new FlowLayout(java.awt.FlowLayout.LEFT, 0, 0)); JButton button = new JButton(cloneModelsAction); PanelUtils.setupComponent(button); toolBar.add(button); panel.add(toolBar, BorderLayout.SOUTH); modelPanelParent = new JPanel(new FlowLayout(FlowLayout.CENTER)); modelPanelParent.setOpaque(false); modelBorder = new TitledBorder("Substitution Model"); modelPanelParent.setBorder(modelBorder); setCurrentModel(null); JScrollPane scrollPane2 = new JScrollPane(modelPanelParent, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane2.setOpaque(false); scrollPane2.setBorder(null); scrollPane2.getViewport().setOpaque(false); JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panel, scrollPane2); splitPane.setDividerLocation(MINIMUM_TABLE_WIDTH); splitPane.setContinuousLayout(true); splitPane.setBorder(BorderFactory.createEmptyBorder()); splitPane.setOpaque(false); setOpaque(false); setBorder(new BorderUIResource.EmptyBorderUIResource(new Insets(12, 12, 12, 12))); setLayout(new BorderLayout(0, 0)); add(splitPane, BorderLayout.CENTER); } private void resetPanel() { if (!options.hasData()) { currentModel = null; modelPanels.clear(); modelPanelParent.removeAll(); modelBorder.setTitle("Substitution Model"); // if (currentDiscreteTraitOption != null) { // this.remove(d_splitPane); // currentDiscreteTraitOption = null; // } return; } } public void setOptions(BeautiOptions options) { if (DEBUG) { Logger.getLogger("dr.app.beauti").info("ModelsPanel.setOptions"); } this.options = options; resetPanel(); settingOptions = true; int selRow = modelTable.getSelectedRow(); modelTableModel.fireTableDataChanged(); if (options.getPartitionSubstitutionModels().size() > 0) { if (selRow < 0) { selRow = 0; } modelTable.getSelectionModel().setSelectionInterval(selRow, selRow); } if (currentModel == null && options.getPartitionSubstitutionModels().size() > 0) { modelTable.getSelectionModel().setSelectionInterval(0, 0); } settingOptions = false; validate(); repaint(); } public void getOptions(BeautiOptions options) { } private void fireModelsChanged() { options.updatePartitionAllLinks(); frame.setDirty(); } private void selectionChanged() { if (modelTable.getSelectedRowCount() == 1) { int selRow = modelTable.getSelectedRow(); if (selRow >= options.getPartitionSubstitutionModels().size()) { selRow = 0; modelTable.getSelectionModel().setSelectionInterval(selRow, selRow); } if (selRow >= 0) { setCurrentModel(options.getPartitionSubstitutionModels().get(selRow)); // frame.modelSelectionChanged(!isUsed(selRow)); } } else { setCurrentModels(getSelectedModels()); } } private List<PartitionSubstitutionModel> getSelectedModels() { java.util.List<PartitionSubstitutionModel> models = new ArrayList<PartitionSubstitutionModel>(); for (int row : modelTable.getSelectedRows()) { models.add(options.getPartitionSubstitutionModels().get(row)); } if (models.size() == 0) { models.addAll(options.getPartitionSubstitutionModels()); } return models; } /** * Sets the current model that this model panel is displaying * * @param model the new model to display */ private void setCurrentModel(PartitionSubstitutionModel model) { modelPanelParent.removeAll(); currentModel = model; if (currentModel != null) { PartitionModelPanel panel = modelPanels.get(currentModel); if (panel == null) { panel = new PartitionModelPanel(currentModel); modelPanels.put(currentModel, panel); } panel.setOptions(); modelPanelParent.add(panel); } else { } cloneModelsAction.setEnabled(true); updateBorder(); } private void setCurrentModels(List<PartitionSubstitutionModel> models) { modelPanelParent.removeAll(); currentModel = null; Set<DataType> dataTypes = new HashSet<DataType>(); for (PartitionSubstitutionModel model : models) { dataTypes.add(model.getDataType()); } if (dataTypes.size() == 1) { DataType dataType = dataTypes.iterator().next(); modelBorder.setTitle("Multiple " + dataType.getName() + " substitution models selected"); } else { modelBorder.setTitle("Multiple mixed type substitution models selected"); } cloneModelsAction.setEnabled(dataTypes.size() == 1); repaint(); } private void updateBorder() { if (currentModel != null) { modelBorder.setTitle(currentModel.getDataType().getName() + " Substitution Model - " + currentModel.getName()); } else { modelBorder.setTitle("Multiple substitution models selected"); } repaint(); } private void cloneModelSettings() { if (cloneModelDialog == null) { cloneModelDialog = new CloneModelDialog(frame); } Set<DataType> dataTypes = new HashSet<DataType>(); for (PartitionSubstitutionModel model : getSelectedModels()) { dataTypes.add(model.getDataType()); } if (dataTypes.size() == 1) { DataType dataType = dataTypes.iterator().next(); List<PartitionSubstitutionModel> sourceModels = new ArrayList<PartitionSubstitutionModel>(); for (PartitionSubstitutionModel model : options.getPartitionSubstitutionModels()) { if (model.getDataType().equals(dataType)) { sourceModels.add(model); } } int result = cloneModelDialog.showDialog(sourceModels); if (result == -1 || result == JOptionPane.CANCEL_OPTION) { return; } PartitionSubstitutionModel sourceModel = cloneModelDialog.getSourceModel(); for (PartitionSubstitutionModel model : getSelectedModels()) { if (!model.equals(sourceModel)) { model.copyFrom(sourceModel); } } repaint(); } } private boolean isUsed(int row) { PartitionSubstitutionModel model = options.getPartitionSubstitutionModels().get(row); for (AbstractPartitionData partition : options.dataPartitions) { if (partition.getPartitionSubstitutionModel() == model) { return true; } } return false; } public JComponent getExportableComponent() { return this; } class ModelTableModel extends AbstractTableModel { /** * */ private static final long serialVersionUID = -6707994233020715574L; String[] columnNames = {"Substitution Model"}; public ModelTableModel() { } public int getColumnCount() { return columnNames.length; } public int getRowCount() { if (options == null) return 0; return options.getPartitionSubstitutionModels().size(); } public Object getValueAt(int row, int col) { PartitionSubstitutionModel model = options.getPartitionSubstitutionModels().get(row); switch (col) { case 0: return model.getName(); default: throw new IllegalArgumentException("unknown column, " + col); } } public boolean isCellEditable(int row, int col) { return true; } public void setValueAt(Object value, int row, int col) { String name = ((String) value).trim(); if (name.length() > 0) { PartitionSubstitutionModel model = options.getPartitionSubstitutionModels().get(row); model.setName(name); //TODO: update every same model in diff PD? updateBorder(); fireModelsChanged(); } } 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(); } } class ModelsTableCellRenderer extends TableRenderer { public ModelsTableCellRenderer(int alignment, Insets insets) { super(alignment, insets); } public Component getTableCellRendererComponent(JTable aTable, Object value, boolean aIsSelected, boolean aHasFocus, int aRow, int aColumn) { if (value == null) return this; Component renderer = super.getTableCellRendererComponent(aTable, value, aIsSelected, aHasFocus, aRow, aColumn); if (!isUsed(aRow)) renderer.setForeground(Color.gray); else renderer.setForeground(Color.black); return this; } } public class CloneModelsAction extends AbstractAction { public CloneModelsAction() { super("Clone Settings..."); setToolTipText("Use this tool to copy settings to selected models"); } public void actionPerformed(ActionEvent ae) { cloneModelSettings(); } } }