/* * AttributeComboHelper.java * * Copyright (C) 2006-2014 Andrew Rambaut * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package figtree.treeviewer.painters; import figtree.treeviewer.TreeViewer; import figtree.treeviewer.TreeViewerListener; import figtree.treeviewer.decorators.ColourDecorator; import jebl.evolution.graphs.Node; import jebl.evolution.taxa.Taxon; import jebl.evolution.trees.Tree; import jebl.util.Attributable; import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.*; /** * @author Andrew Rambaut * @version $Id$ * * $HeadURL$ * * $LastChangedBy$ * $LastChangedDate$ * $LastChangedRevision$ */ public class AttributeComboHelper { public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer) { this(attributeComboBox, treeViewer, null, null, false, false); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final String defaultOption) { this(attributeComboBox, treeViewer, defaultOption, null, false, false); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final String defaultOption, final LabelPainter.PainterIntent intent) { this(attributeComboBox, treeViewer, defaultOption, intent, false, false); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final String defaultOption, final boolean numericalOnly, final boolean includeLineageColourings) { this(attributeComboBox, treeViewer, defaultOption, null, numericalOnly, includeLineageColourings); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final LabelPainter.PainterIntent intent) { this(attributeComboBox, treeViewer, null, intent, false, false); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final LabelPainter.PainterIntent intent, final boolean numericalOnly) { this(attributeComboBox, treeViewer, null, intent, numericalOnly, false); } public AttributeComboHelper(final JComboBox attributeComboBox, final TreeViewer treeViewer, final String defaultOption, final LabelPainter.PainterIntent intent, final boolean numericalOnly, final boolean includeLineageColourings) { treeViewer.addTreeViewerListener(new TreeViewerListener() { public void treeChanged() { List<Tree> trees = treeViewer.getTrees(); Object selected = attributeComboBox.getSelectedItem(); addingItems = true; attributeComboBox.removeAllItems(); if (defaultOption != null) { attributeComboBox.addItem(defaultOption); } if (trees == null) { return; } List<String> names = new ArrayList<String>(); if (intent != null || numericalOnly) { getAttributeNames(names, trees, intent, numericalOnly); } else { getAttributeNames(names, trees, includeLineageColourings); } for (String name : names) { attributeComboBox.addItem(name); } addingItems = false; if (selected != null) { attributeComboBox.setSelectedItem(selected); } } public void treeSettingsChanged() { // nothing to do } }); attributeComboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { if (!addingItems) { fireAttributeSelectionChanged(); } } }); } public static void getAttributeNames(List<String> attributeNames, Collection<? extends Tree> trees, LabelPainter.PainterIntent intent, boolean numericalOnly) { Set<String> nodeAttributes = new TreeSet<String>(); if (trees != null) { for (Tree tree : trees) { if (intent == LabelPainter.PainterIntent.TIP) { for (Node node : tree.getExternalNodes()) { nodeAttributes.addAll(node.getAttributeNames()); } for (Taxon taxon : tree.getTaxa()) { nodeAttributes.addAll(taxon.getAttributeNames()); } } else if (intent == LabelPainter.PainterIntent.NODE) { for (Node node : tree.getInternalNodes()) { nodeAttributes.addAll(node.getAttributeNames()); } } else if (intent == LabelPainter.PainterIntent.RANGE) { for (Node node : tree.getInternalNodes()) { for (String name : node.getAttributeNames()) { Object attr = node.getAttribute(name); if (attr instanceof Object[]) { Object[] array = (Object[])attr; if (array.length == 2 && array[0] instanceof Number && array[1] instanceof Number) { nodeAttributes.add(name); } } } } } else { for (Node node : tree.getNodes()) { for (String key : node.getAttributeMap().keySet()) { nodeAttributes.add(key); } } } } } if (numericalOnly) { Set<String> continuousNodeAttributes = new TreeSet<String>(); for (String nodeAttributeName : nodeAttributes) { boolean isNumerical = true; for (Tree tree : trees) { if (!ColourDecorator.isNumerical(nodeAttributeName, tree.getNodes())) { isNumerical = false; } } if (isNumerical) { continuousNodeAttributes.add(nodeAttributeName); } } nodeAttributes = continuousNodeAttributes; } if (intent != null) { switch( intent ) { case TIP: { attributeNames.add(LabelPainter.NAMES); attributeNames.add(LabelPainter.NODE_AGES); attributeNames.add(LabelPainter.NODE_HEIGHTS); attributeNames.add(LabelPainter.BRANCH_TIMES); attributeNames.add(LabelPainter.BRANCH_LENGTHS); break; } case NODE: { if (nodeAttributes.contains("!name")) { attributeNames.add(LabelPainter.NAMES); } attributeNames.add(LabelPainter.NODE_AGES); attributeNames.add(LabelPainter.NODE_HEIGHTS); attributeNames.add(LabelPainter.BRANCH_TIMES); attributeNames.add(LabelPainter.BRANCH_LENGTHS); break; } case BRANCH: { if (nodeAttributes.contains("!name")) { attributeNames.add(LabelPainter.NAMES); } attributeNames.add(LabelPainter.BRANCH_TIMES); attributeNames.add(LabelPainter.BRANCH_LENGTHS); attributeNames.add(LabelPainter.NODE_AGES); attributeNames.add(LabelPainter.NODE_HEIGHTS); break; } } } for (String attributeName : nodeAttributes) { if (!attributeName.startsWith("!")) { attributeNames.add(attributeName); } } } private static void getAttributeNames(List<String> attributeNames, Collection<? extends Tree> trees, final boolean includeLineageColourings) { for (Tree tree : trees) { Set<String> attributes = new TreeSet<String>(); for (Attributable item : tree.getNodes()) { for (String name : item.getAttributeNames()) { if (!name.startsWith("!")) { Object attr = item.getAttribute(name); if (!(attr instanceof Object[])) { attributes.add(name); } else { boolean isColouring = true; Object[] array = (Object[])attr; boolean isIndex = true; for (Object element : array) { if (isIndex && !(element instanceof Integer) || !isIndex && !(element instanceof Double)) { isColouring = false; break; } isIndex = !isIndex; } if (isIndex) { // a colouring should finish on an index (which means isIndex should be false)... isColouring = false; } if (isColouring && includeLineageColourings) { attributes.add(name + " *"); } } } } } attributeNames.addAll(attributes); } } public void addListener(AttributeComboHelperListener listener) { listeners.add(listener); } private void fireAttributeSelectionChanged() { for (AttributeComboHelperListener listener : listeners) { listener.attributeComboChanged(); } } private final List<AttributeComboHelperListener> listeners = new ArrayList<AttributeComboHelperListener>(); private boolean addingItems = false; }