/* * CharactersPanel.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.treestat; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.util.ArrayList; import dr.app.gui.table.TableSorter; import jam.table.TableRenderer; import jam.framework.Exportable; public class CharactersPanel extends JPanel implements Exportable { /** * */ private static final long serialVersionUID = 1063807543195481382L; TreeStatFrame frame = null; TreeStatData treeStatData = null; TreeStatData.Character selectedCharacter = null; TreeStatData.State selectedState = null; JScrollPane scrollPane1 = new JScrollPane(); JTable charactersTable = null; CharactersTableModel charactersTableModel = null; JScrollPane scrollPane2 = new JScrollPane(); JTable statesTable = null; StatesTableModel statesTableModel = null; JScrollPane scrollPane3 = new JScrollPane(); JTable excludedTaxaTable = null; TaxaTableModel excludedTaxaTableModel = null; JScrollPane scrollPane4 = new JScrollPane(); JTable includedTaxaTable = null; TaxaTableModel includedTaxaTableModel = null; public CharactersPanel(TreeStatFrame frame, TreeStatData treeStatData) { this.frame = frame; setOpaque(false); this.treeStatData = treeStatData; Icon addIcon = null, removeIcon = null, includeIcon = null, excludeIcon = null; try { addIcon = new ImageIcon(dr.app.util.Utils.getImage(this, "images/add.png")); removeIcon = new ImageIcon(dr.app.util.Utils.getImage(this, "images/minus.png")); includeIcon = new ImageIcon(dr.app.util.Utils.getImage(this, "images/include.png")); excludeIcon = new ImageIcon(dr.app.util.Utils.getImage(this, "images/exclude.png")); } catch (Exception e) { // do nothing } // Characters charactersTableModel = new CharactersTableModel(); TableSorter sorter = new TableSorter(charactersTableModel); charactersTable = new JTable(sorter); sorter.addTableModelListener(charactersTable); charactersTable.getColumnModel().getColumn(0).setCellRenderer( new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); charactersTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { charactersTableSelectionChanged(); } }); scrollPane1 = new JScrollPane(charactersTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JPanel buttonPanel1 = createAddRemoveButtonPanel(addCharacterAction, addIcon, "Create a new character", removeCharacterAction, removeIcon, "Remove a character", javax.swing.BoxLayout.X_AXIS); // States statesTableModel = new StatesTableModel(); sorter = new TableSorter(statesTableModel); statesTable = new JTable(sorter); sorter.addTableModelListener(statesTable); statesTable.getColumnModel().getColumn(0).setCellRenderer( new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); statesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { statesTableSelectionChanged(); } }); scrollPane2 = new JScrollPane(statesTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JPanel buttonPanel2 = createAddRemoveButtonPanel(addStateAction, addIcon, "Create a new state", removeStateAction, removeIcon, "Remove a state", javax.swing.BoxLayout.X_AXIS); // Excluded Taxon List excludedTaxaTableModel = new TaxaTableModel(false); sorter = new TableSorter(excludedTaxaTableModel); excludedTaxaTable = new JTable(sorter); sorter.addTableModelListener(excludedTaxaTable); excludedTaxaTable.getColumnModel().getColumn(0).setCellRenderer( new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); excludedTaxaTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { excludedTaxaTableSelectionChanged(); } }); scrollPane3 = new JScrollPane(excludedTaxaTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); JPanel buttonPanel3 = createAddRemoveButtonPanel(includeTaxonAction, includeIcon, "Include selected taxa in the taxon set", excludeTaxonAction, excludeIcon, "Exclude selected taxa from the taxon set", javax.swing.BoxLayout.Y_AXIS); // Included Taxon List includedTaxaTableModel = new TaxaTableModel(true); sorter = new TableSorter(includedTaxaTableModel); includedTaxaTable = new JTable(sorter); sorter.addTableModelListener(includedTaxaTable); includedTaxaTable.getColumnModel().getColumn(0).setCellRenderer( new TableRenderer(SwingConstants.LEFT, new Insets(0, 4, 0, 4))); includedTaxaTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { includedTaxaTableSelectionChanged(); } }); scrollPane4 = new JScrollPane(includedTaxaTable, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.weightx = 0.333333; c.weighty = 1; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(6,6,6,6); c.gridx = 0; c.gridy = 0; c.gridwidth = 1; c.gridheight = 3; add(scrollPane1, c); c.weightx = 0.333333; c.weighty = 0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(0,6,6,6); c.gridx = 0; c.gridy = 3; c.gridwidth = 1; c.gridheight = 1; add(buttonPanel1, c); c.weightx = 0.666664; c.weighty = 0.333333; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(6,6,6,6); c.gridx = 1; c.gridy = 0; c.gridwidth = 3; c.gridheight = 1; add(scrollPane2, c); c.weightx = 0.666664; c.weighty = 0; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.LINE_START; c.insets = new Insets(0,6,6,6); c.gridx = 1; c.gridy = 1; c.gridwidth = 3; c.gridheight = 1; add(buttonPanel2, c); c.weightx = 0.333333; c.weighty = 0.666664; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(6,6,6,6); c.gridx = 1; c.gridy = 2; c.gridwidth = 1; c.gridheight = 1; add(scrollPane3, c); c.weightx = 0.0; c.weighty = 0.666664; c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(0,0,0,0); c.gridx = 2; c.gridy = 2; c.gridwidth = 1; c.gridheight = 1; add(buttonPanel3, c); c.weightx = 0.333333; c.weighty = 0.666664; c.fill = GridBagConstraints.BOTH; c.anchor = GridBagConstraints.CENTER; c.insets = new Insets(6,6,6,6); c.gridx = 3; c.gridy = 2; c.gridwidth = 1; c.gridheight = 1; add(scrollPane4, c); setBorder(BorderFactory.createEmptyBorder(6,6,6,6)); } JPanel createAddRemoveButtonPanel(Action addAction, Icon addIcon, String addToolTip, Action removeAction, Icon removeIcon, String removeToolTip, int axis) { JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, axis)); buttonPanel.setOpaque(false); JButton addButton = new JButton(addAction); if (addIcon != null) { addButton.setIcon(addIcon); addButton.setText(null); } addButton.setToolTipText(addToolTip); addButton.putClientProperty("JButton.buttonType", "toolbar"); addButton.setOpaque(false); addAction.setEnabled(false); JButton removeButton = new JButton(removeAction); if (removeIcon != null) { removeButton.setIcon(removeIcon); removeButton.setText(null); } removeButton.setToolTipText(removeToolTip); removeButton.putClientProperty("JButton.buttonType", "toolbar"); removeButton.setOpaque(false); removeAction.setEnabled(false); buttonPanel.add(addButton); buttonPanel.add(new JToolBar.Separator(new Dimension(6,6))); buttonPanel.add(removeButton); return buttonPanel; } public void dataChanged() { addCharacterAction.setEnabled(treeStatData.allTaxa.size() > 0); charactersTableModel.fireTableDataChanged(); statesTableModel.fireTableDataChanged(); includedTaxaTableModel.fireTableDataChanged(); excludedTaxaTableModel.fireTableDataChanged(); } private void charactersTableSelectionChanged() { if (charactersTable.getSelectedRowCount() == 0) { selectedCharacter = null; removeCharacterAction.setEnabled(false); addStateAction.setEnabled(false); } else { selectedCharacter = treeStatData.characters.get(charactersTable.getSelectedRow()); removeCharacterAction.setEnabled(true); addStateAction.setEnabled(true); } includedTaxaTableModel.fireTableDataChanged(); excludedTaxaTableModel.fireTableDataChanged(); } private void statesTableSelectionChanged() { if (statesTable.getSelectedRowCount() == 0) { selectedState = null; removeStateAction.setEnabled(false); } else { selectedCharacter = null; removeStateAction.setEnabled(true); } includedTaxaTableModel.fireTableDataChanged(); excludedTaxaTableModel.fireTableDataChanged(); } private void excludedTaxaTableSelectionChanged() { if (excludedTaxaTable.getSelectedRowCount() == 0) { includeTaxonAction.setEnabled(false); } else { includeTaxonAction.setEnabled(true); } } private void includedTaxaTableSelectionChanged() { if (includedTaxaTable.getSelectedRowCount() == 0) { excludeTaxonAction.setEnabled(false); } else { excludeTaxonAction.setEnabled(true); } } public JComponent getExportableComponent() { return this; } Action addCharacterAction = new AbstractAction("Add") { /** * */ private static final long serialVersionUID = -2222139644754040949L; public void actionPerformed(ActionEvent ae) { TreeStatData.Character character = new TreeStatData.Character(); character.name = "untitled"; character.states = new ArrayList<TreeStatData.State>(); treeStatData.characters.add(character); dataChanged(); int sel = treeStatData.characters.size() - 1; charactersTable.setRowSelectionInterval(sel, sel); } }; Action removeCharacterAction = new AbstractAction("Remove") { /** * */ private static final long serialVersionUID = -6836455052115579291L; public void actionPerformed(ActionEvent ae) { int saved = charactersTable.getSelectedRow(); int row = charactersTable.getSelectedRow(); if (row != -1) { treeStatData.characters.remove(row); } dataChanged(); if (saved >= treeStatData.characters.size()) saved = treeStatData.characters.size() - 1; charactersTable.setRowSelectionInterval(saved, saved); } }; Action addStateAction = new AbstractAction("Add") { /** * */ private static final long serialVersionUID = -2304872597649350237L; public void actionPerformed(ActionEvent ae) { } }; Action removeStateAction = new AbstractAction("Remove") { /** * */ private static final long serialVersionUID = -6390058458520173491L; public void actionPerformed(ActionEvent ae) { } }; Action includeTaxonAction = new AbstractAction("->") { /** * */ private static final long serialVersionUID = 4577920870740752531L; public void actionPerformed(ActionEvent ae) { int saved1 = charactersTable.getSelectedRow(); int saved2 = statesTable.getSelectedRow(); int[] rows = excludedTaxaTable.getSelectedRows(); ArrayList<String> exclList = new ArrayList<String>(treeStatData.allTaxa); exclList.removeAll(selectedState.taxa); for (int row : rows) { selectedState.taxa.add(exclList.get(row)); } dataChanged(); charactersTable.setRowSelectionInterval(saved1, saved1); statesTable.setRowSelectionInterval(saved2, saved2); } }; Action excludeTaxonAction = new AbstractAction("<-") { /** * */ private static final long serialVersionUID = 7911132810956409390L; public void actionPerformed(ActionEvent ae) { int saved1 = charactersTable.getSelectedRow(); int saved2 = statesTable.getSelectedRow(); int[] rows = includedTaxaTable.getSelectedRows(); for (int i = rows.length - 1; i >= 0 ; i--) { selectedState.taxa.remove(rows[i]); } dataChanged(); charactersTable.setRowSelectionInterval(saved1, saved1); statesTable.setRowSelectionInterval(saved2, saved2); } }; class CharactersTableModel extends AbstractTableModel { /** * */ private static final long serialVersionUID = -3916166866378281436L; public CharactersTableModel() { } public int getColumnCount() { return 1; } public int getRowCount() { return treeStatData.characters.size(); } public Object getValueAt(int row, int col) { return treeStatData.characters.get(row).name; } public void setValueAt(Object value, int row, int col) { treeStatData.characters.get(row).name = (String)value; } public boolean isCellEditable(int row, int col) { return true; } public String getColumnName(int column) { return "Characters"; } public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} } class StatesTableModel extends AbstractTableModel { /** * */ private static final long serialVersionUID = -1912262346368463655L; String[] columnNames = new String[] { "State", "Description" }; public StatesTableModel() { } public int getColumnCount() { return 2; } public int getRowCount() { if (selectedCharacter == null) return 0; return selectedCharacter.states.size(); } public Object getValueAt(int row, int col) { final TreeStatData.State state = selectedCharacter.states.get(row); if (col == 0) { return state.name; } else { return state.description; } } public void setValueAt(Object value, int row, int col) { final TreeStatData.State state = selectedCharacter.states.get(row); if (col == 0) { state.name = (String)value; } else { state.description = (String)value; } } public boolean isCellEditable(int row, int col) { return true; } public String getColumnName(int col) { return columnNames[col]; } public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} } class TaxaTableModel extends AbstractTableModel { /** * */ private static final long serialVersionUID = 2786966293840685962L; boolean included; public TaxaTableModel(boolean included) { this.included = included; } public int getColumnCount() { return 1; } public int getRowCount() { if (selectedState == null || treeStatData.allTaxa == null) return 0; if (included) { return selectedState.taxa.size(); } else { return treeStatData.allTaxa.size() - selectedState.taxa.size(); } } public Object getValueAt(int row, int col) { if (included) { return selectedState.taxa.get(row); } else { ArrayList<String> exclList = new ArrayList<String>(treeStatData.allTaxa); exclList.removeAll(selectedState.taxa); return exclList.get(row); } } public boolean isCellEditable(int row, int col) { return false; } public String getColumnName(int column) { if (included) return "Included Taxa"; else return "Excluded Taxa"; } public Class getColumnClass(int c) {return getValueAt(0, c).getClass();} } }