/* * SimpleLabelPainter.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.panel; import figtree.treeviewer.TreePane; import figtree.treeviewer.painters.LabelPainter; import figtree.treeviewer.decorators.Decorator; import jebl.evolution.graphs.Node; import jebl.evolution.taxa.Taxon; import jebl.evolution.trees.RootedTree; import jebl.evolution.trees.Tree; import jebl.util.Attributable; import java.awt.*; import java.awt.geom.Rectangle2D; import java.util.*; import java.util.List; /** * A simple implementation of LabelPainter that can be used to display * tip, node or branch labels. It can display, taxon names, branch lengths, * node heights or other attributeNames of nodes. * * @author Andrew Rambaut * @version $Id$ * * $HeadURL$ * * $LastChangedBy$ * $LastChangedDate$ * $LastChangedRevision$ */ public class SimpleLabelPainter extends LabelPainter<Node> { public static final String NAMES = "Names"; public static final String NODE_AGES = "Node ages"; public static final String BRANCH_LENGTHS = "Branch lengths"; public SimpleLabelPainter(PainterIntent intent) { super(intent); setupAttributes(null); if (this.displayAttribute == null) { this.displayAttribute = attributes[0]; } else { this.displayAttribute = ""; } } public void setupAttributes(Collection<? extends Tree> trees) { List<String> attributeNames = new ArrayList<String>(); switch (getIntent()) { case TIP: { attributeNames.add(NAMES); attributeNames.add(NODE_AGES); attributeNames.add(BRANCH_LENGTHS); break; } case NODE: { attributeNames.add(NODE_AGES); attributeNames.add(BRANCH_LENGTHS); break; } case BRANCH: { attributeNames.add(BRANCH_LENGTHS); attributeNames.add(NODE_AGES); break; } } if (trees != null) { for (Tree tree : trees) { Set<String> nodeAttributes = new TreeSet<String>(); if (getIntent() == PainterIntent.TIP) { for (Node node : tree.getExternalNodes()) { nodeAttributes.addAll(node.getAttributeNames()); } } else if (getIntent() == PainterIntent.NODE) { for (Node node : tree.getInternalNodes()) { nodeAttributes.addAll(node.getAttributeNames()); } } else { for (Node node : tree.getNodes()) { nodeAttributes.addAll(node.getAttributeNames()); } } for (String attributeName : nodeAttributes) { if (!attributeName.startsWith("!")) { attributeNames.add(attributeName); } } } } this.attributes = new String[attributeNames.size()]; attributeNames.toArray(this.attributes); firePainterSettingsChanged(); } public void setTreePane(TreePane treePane) { this.treePane = treePane; } public Decorator getBorderDecorator() { return borderDecorator; } public void setBorderDecorator(Decorator borderDecorator) { this.borderDecorator = borderDecorator; } public Decorator getTextDecorator() { return textDecorator; } public void setTextDecorator(Decorator textDecorator) { this.textDecorator = textDecorator; } public Set<Attributable> getAttributableItems() { return null; } public Tree getTree() { return treePane.getTree(); } protected String getLabel(Tree tree, Node node) { if (displayAttribute.equalsIgnoreCase(NAMES)) { Taxon taxon = tree.getTaxon(node); if (taxon != null) { if (textDecorator != null) { textDecorator.setItem(taxon); } return taxon.getName(); } else { String name = (String)node.getAttribute("name"); if (name != null) { return name; } return "unlabelled"; } } if ( tree instanceof RootedTree) { final RootedTree rtree = (RootedTree) tree; if (textDecorator != null) { textDecorator.setItem(node); } if (displayAttribute.equalsIgnoreCase(NODE_AGES) ) { return getNumberFormat().format(rtree.getHeight(node)); } else if (displayAttribute.equalsIgnoreCase(BRANCH_LENGTHS) ) { return getNumberFormat().format(rtree.getLength(node)); } } return formatValue(node.getAttribute(displayAttribute)); } private String formatValue(Object value) { if (value != null) { if (value instanceof Double) { return getNumberFormat().format(value); } else if (value instanceof Object[]) { Object[] values = (Object[])value; if (values.length == 0) return null; if (values.length == 1) return formatValue(values[0]); StringBuilder builder = new StringBuilder("["); builder.append(formatValue(values[0])); for (int i = 1; i < values.length; i++) { builder.append(","); builder.append(formatValue(values[i])); } builder.append("]"); return builder.toString(); } return value.toString(); } return null; } public Rectangle2D calibrate(Graphics2D g2, Node item) { Tree tree = treePane.getTree(); String label = getLabel(tree, item); final Font oldFont = g2.getFont(); if (textDecorator != null) { g2.setFont(textDecorator.getFont(getFont())); } else { g2.setFont(getFont()); } FontMetrics fm = g2.getFontMetrics(); preferredHeight = fm.getHeight(); preferredWidth = 0; if (label != null) { Rectangle2D rect = fm.getStringBounds(label, g2); preferredWidth = rect.getWidth(); } yOffset = (float)fm.getAscent(); g2.setFont(oldFont); return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); } public double getPreferredWidth() { return preferredWidth; } public double getPreferredHeight() { return preferredHeight; } public double getHeightBound() { return preferredHeight + yOffset; } public void paint(Graphics2D g2, Node item, Justification justification, Rectangle2D bounds) { Tree tree = treePane.getTree(); if (TreePane.DEBUG_OUTLINE) { g2.setPaint(Color.red); g2.draw(bounds); } String label = getLabel(tree, item); Font oldFont = g2.getFont(); Paint backgroundPaint = getBackground(); Paint borderPaint = getBorderPaint(); Stroke borderStroke = getBorderStroke(); if (borderDecorator != null) { backgroundPaint = borderDecorator.getPaint(backgroundPaint); borderPaint = borderDecorator.getPaint(borderPaint); borderStroke = borderDecorator.getStroke(borderStroke); } if (backgroundPaint != null) { g2.setPaint(backgroundPaint); g2.fill(bounds); } if (borderPaint != null && borderStroke != null) { g2.setPaint(borderPaint); g2.setStroke(borderStroke); g2.draw(bounds); } if (textDecorator != null) { g2.setPaint(textDecorator.getPaint(getForeground())); g2.setFont(textDecorator.getFont(getFont())); } else { g2.setPaint(getForeground()); g2.setFont(getFont()); } if (label != null) { Rectangle2D rect = null; if (justification == Justification.CENTER || justification == Justification.RIGHT) rect = g2.getFontMetrics().getStringBounds(label, g2); float xOffset; float y = yOffset + (float) bounds.getY(); switch (justification) { case CENTER: xOffset = (float)(-rect.getWidth()/2.0); y = yOffset + (float) rect.getY(); //xOffset = (float) (bounds.getX() + (bounds.getWidth() - rect.getWidth()) / 2.0); break; case FLUSH: case LEFT: xOffset = (float) bounds.getX(); break; case RIGHT: xOffset = (float) (bounds.getX() + bounds.getWidth() - rect.getWidth()); break; default: throw new IllegalArgumentException("Unrecognized alignment enum option"); } g2.drawString(label, xOffset, y); } g2.setFont(oldFont); } public String[] getAttributes() { return attributes; } public String getDisplayAttribute() { return displayAttribute; } public void setDisplayAttribute(String displayAttribute) { this.displayAttribute = displayAttribute; firePainterChanged(); } private double preferredWidth; private double preferredHeight; private float yOffset; protected String displayAttribute; protected String[] attributes; protected TreePane treePane; private Decorator textDecorator = null; private Decorator borderDecorator = null; }