1 /* 2 * SimpleLabelPainter.java 3 * 4 * Copyright (C) 2006-2014 Andrew Rambaut 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 2 9 * of the License, or (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21 package figtree.panel; 22 23 import figtree.treeviewer.TreePane; 24 import figtree.treeviewer.painters.LabelPainter; 25 import figtree.treeviewer.decorators.Decorator; 26 import jebl.evolution.graphs.Node; 27 import jebl.evolution.taxa.Taxon; 28 import jebl.evolution.trees.RootedTree; 29 import jebl.evolution.trees.Tree; 30 import jebl.util.Attributable; 31 32 import java.awt.*; 33 import java.awt.geom.Rectangle2D; 34 import java.util.*; 35 import java.util.List; 36 37 /** 38 * A simple implementation of LabelPainter that can be used to display 39 * tip, node or branch labels. It can display, taxon names, branch lengths, 40 * node heights or other attributeNames of nodes. 41 * 42 * @author Andrew Rambaut 43 * @version $Id$ 44 * 45 * $HeadURL$ 46 * 47 * $LastChangedBy$ 48 * $LastChangedDate$ 49 * $LastChangedRevision$ 50 */ 51 public class SimpleLabelPainter extends LabelPainter<Node> { 52 53 public static final String NAMES = "Names"; 54 public static final String NODE_AGES = "Node ages"; 55 public static final String BRANCH_LENGTHS = "Branch lengths"; 56 SimpleLabelPainter(PainterIntent intent)57 public SimpleLabelPainter(PainterIntent intent) { 58 super(intent); 59 60 setupAttributes(null); 61 62 if (this.displayAttribute == null) { 63 this.displayAttribute = attributes[0]; 64 } else { 65 this.displayAttribute = ""; 66 } 67 68 } 69 setupAttributes(Collection<? extends Tree> trees)70 public void setupAttributes(Collection<? extends Tree> trees) { 71 72 List<String> attributeNames = new ArrayList<String>(); 73 switch (getIntent()) { 74 case TIP: { 75 attributeNames.add(NAMES); 76 attributeNames.add(NODE_AGES); 77 attributeNames.add(BRANCH_LENGTHS); 78 break; 79 } 80 case NODE: { 81 attributeNames.add(NODE_AGES); 82 attributeNames.add(BRANCH_LENGTHS); 83 break; 84 } 85 case BRANCH: { 86 attributeNames.add(BRANCH_LENGTHS); 87 attributeNames.add(NODE_AGES); 88 break; 89 } 90 } 91 92 if (trees != null) { 93 for (Tree tree : trees) { 94 Set<String> nodeAttributes = new TreeSet<String>(); 95 if (getIntent() == PainterIntent.TIP) { 96 for (Node node : tree.getExternalNodes()) { 97 nodeAttributes.addAll(node.getAttributeNames()); 98 } 99 } else if (getIntent() == PainterIntent.NODE) { 100 for (Node node : tree.getInternalNodes()) { 101 nodeAttributes.addAll(node.getAttributeNames()); 102 } 103 } else { 104 for (Node node : tree.getNodes()) { 105 nodeAttributes.addAll(node.getAttributeNames()); 106 } 107 } 108 for (String attributeName : nodeAttributes) { 109 if (!attributeName.startsWith("!")) { 110 attributeNames.add(attributeName); 111 } 112 } 113 } 114 } 115 116 this.attributes = new String[attributeNames.size()]; 117 attributeNames.toArray(this.attributes); 118 119 firePainterSettingsChanged(); 120 } 121 setTreePane(TreePane treePane)122 public void setTreePane(TreePane treePane) { 123 this.treePane = treePane; 124 } 125 getBorderDecorator()126 public Decorator getBorderDecorator() { 127 return borderDecorator; 128 } 129 setBorderDecorator(Decorator borderDecorator)130 public void setBorderDecorator(Decorator borderDecorator) { 131 this.borderDecorator = borderDecorator; 132 } 133 getTextDecorator()134 public Decorator getTextDecorator() { 135 return textDecorator; 136 } 137 setTextDecorator(Decorator textDecorator)138 public void setTextDecorator(Decorator textDecorator) { 139 this.textDecorator = textDecorator; 140 } 141 getAttributableItems()142 public Set<Attributable> getAttributableItems() { 143 return null; 144 } 145 getTree()146 public Tree getTree() { 147 return treePane.getTree(); 148 } 149 getLabel(Tree tree, Node node)150 protected String getLabel(Tree tree, Node node) { 151 if (displayAttribute.equalsIgnoreCase(NAMES)) { 152 Taxon taxon = tree.getTaxon(node); 153 if (taxon != null) { 154 if (textDecorator != null) { 155 textDecorator.setItem(taxon); 156 } 157 return taxon.getName(); 158 } else { 159 String name = (String)node.getAttribute("name"); 160 if (name != null) { 161 return name; 162 } 163 return "unlabelled"; 164 } 165 } 166 167 if ( tree instanceof RootedTree) { 168 final RootedTree rtree = (RootedTree) tree; 169 170 if (textDecorator != null) { 171 textDecorator.setItem(node); 172 } 173 174 if (displayAttribute.equalsIgnoreCase(NODE_AGES) ) { 175 return getNumberFormat().format(rtree.getHeight(node)); 176 } else if (displayAttribute.equalsIgnoreCase(BRANCH_LENGTHS) ) { 177 return getNumberFormat().format(rtree.getLength(node)); 178 } 179 } 180 181 return formatValue(node.getAttribute(displayAttribute)); 182 } 183 formatValue(Object value)184 private String formatValue(Object value) { 185 if (value != null) { 186 if (value instanceof Double) { 187 return getNumberFormat().format(value); 188 } else if (value instanceof Object[]) { 189 Object[] values = (Object[])value; 190 191 if (values.length == 0) return null; 192 if (values.length == 1) return formatValue(values[0]); 193 194 StringBuilder builder = new StringBuilder("["); 195 builder.append(formatValue(values[0])); 196 for (int i = 1; i < values.length; i++) { 197 builder.append(","); 198 builder.append(formatValue(values[i])); 199 } 200 builder.append("]"); 201 return builder.toString(); 202 } 203 return value.toString(); 204 } 205 return null; 206 } 207 calibrate(Graphics2D g2, Node item)208 public Rectangle2D calibrate(Graphics2D g2, Node item) { 209 Tree tree = treePane.getTree(); 210 211 String label = getLabel(tree, item); 212 213 final Font oldFont = g2.getFont(); 214 if (textDecorator != null) { 215 g2.setFont(textDecorator.getFont(getFont())); 216 } else { 217 g2.setFont(getFont()); 218 } 219 220 FontMetrics fm = g2.getFontMetrics(); 221 preferredHeight = fm.getHeight(); 222 preferredWidth = 0; 223 224 if (label != null) { 225 Rectangle2D rect = fm.getStringBounds(label, g2); 226 preferredWidth = rect.getWidth(); 227 } 228 229 yOffset = (float)fm.getAscent(); 230 231 g2.setFont(oldFont); 232 233 return new Rectangle2D.Double(0.0, 0.0, preferredWidth, preferredHeight); 234 } 235 getPreferredWidth()236 public double getPreferredWidth() { 237 return preferredWidth; 238 } 239 getPreferredHeight()240 public double getPreferredHeight() { 241 return preferredHeight; 242 } 243 getHeightBound()244 public double getHeightBound() { 245 return preferredHeight + yOffset; 246 } 247 paint(Graphics2D g2, Node item, Justification justification, Rectangle2D bounds)248 public void paint(Graphics2D g2, Node item, Justification justification, Rectangle2D bounds) { 249 Tree tree = treePane.getTree(); 250 251 if (TreePane.DEBUG_OUTLINE) { 252 g2.setPaint(Color.red); 253 g2.draw(bounds); 254 } 255 256 String label = getLabel(tree, item); 257 258 Font oldFont = g2.getFont(); 259 260 Paint backgroundPaint = getBackground(); 261 Paint borderPaint = getBorderPaint(); 262 Stroke borderStroke = getBorderStroke(); 263 264 if (borderDecorator != null) { 265 backgroundPaint = borderDecorator.getPaint(backgroundPaint); 266 borderPaint = borderDecorator.getPaint(borderPaint); 267 borderStroke = borderDecorator.getStroke(borderStroke); 268 } 269 270 if (backgroundPaint != null) { 271 g2.setPaint(backgroundPaint); 272 g2.fill(bounds); 273 } 274 275 if (borderPaint != null && borderStroke != null) { 276 g2.setPaint(borderPaint); 277 g2.setStroke(borderStroke); 278 g2.draw(bounds); 279 } 280 281 if (textDecorator != null) { 282 g2.setPaint(textDecorator.getPaint(getForeground())); 283 g2.setFont(textDecorator.getFont(getFont())); 284 } else { 285 g2.setPaint(getForeground()); 286 g2.setFont(getFont()); 287 } 288 289 if (label != null) { 290 291 Rectangle2D rect = null; 292 if (justification == Justification.CENTER || justification == Justification.RIGHT) 293 rect = g2.getFontMetrics().getStringBounds(label, g2); 294 295 float xOffset; 296 float y = yOffset + (float) bounds.getY(); 297 switch (justification) { 298 case CENTER: 299 xOffset = (float)(-rect.getWidth()/2.0); 300 y = yOffset + (float) rect.getY(); 301 //xOffset = (float) (bounds.getX() + (bounds.getWidth() - rect.getWidth()) / 2.0); 302 break; 303 case FLUSH: 304 case LEFT: 305 xOffset = (float) bounds.getX(); 306 break; 307 case RIGHT: 308 xOffset = (float) (bounds.getX() + bounds.getWidth() - rect.getWidth()); 309 break; 310 default: 311 throw new IllegalArgumentException("Unrecognized alignment enum option"); 312 } 313 314 g2.drawString(label, xOffset, y); 315 } 316 317 g2.setFont(oldFont); 318 } 319 getAttributes()320 public String[] getAttributes() { 321 return attributes; 322 } 323 getDisplayAttribute()324 public String getDisplayAttribute() { 325 return displayAttribute; 326 } 327 setDisplayAttribute(String displayAttribute)328 public void setDisplayAttribute(String displayAttribute) { 329 this.displayAttribute = displayAttribute; 330 firePainterChanged(); 331 } 332 333 private double preferredWidth; 334 private double preferredHeight; 335 private float yOffset; 336 337 protected String displayAttribute; 338 protected String[] attributes; 339 340 protected TreePane treePane; 341 342 private Decorator textDecorator = null; 343 private Decorator borderDecorator = null; 344 345 }