1 /* 2 * MultiPaneTreeViewer.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.treeviewer; 22 23 import figtree.treeviewer.painters.*; 24 import jebl.evolution.trees.*; 25 import jebl.evolution.graphs.Node; 26 import figtree.treeviewer.treelayouts.TreeLayout; 27 import figtree.treeviewer.decorators.Decorator; 28 29 import javax.swing.*; 30 import java.awt.*; 31 import java.awt.print.*; 32 import java.util.*; 33 34 import jam.panels.StatusProvider; 35 36 /** 37 * @author Andrew Rambaut 38 * @version $Id$ 39 * 40 * $HeadURL$ 41 * 42 * $LastChangedBy$ 43 * $LastChangedDate$ 44 * $LastChangedRevision$ 45 */ 46 public class MultiPaneTreeViewer extends TreeViewer { 47 48 private final static double MAX_ZOOM = 20; 49 private final static double MAX_VERTICAL_EXPANSION = 20; 50 51 /** 52 * Creates new TreeViewer 53 */ MultiPaneTreeViewer()54 public MultiPaneTreeViewer() { 55 treePanes.add(new TreePane()); 56 57 setLayout(new BorderLayout()); 58 59 treePanePanel = new MultiPaneTreePanel(); 60 treePanePanel.setLayout(new BoxLayout(treePanePanel, BoxLayout.PAGE_AXIS)); 61 62 JScrollPane scrollPane = new JScrollPane(treePanePanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 63 scrollPane.setMinimumSize(new Dimension(150, 150)); 64 65 scrollPane.setBorder(null); 66 viewport = scrollPane.getViewport(); 67 68 add(scrollPane, BorderLayout.CENTER); 69 70 } 71 setTree(Tree tree)72 public void setTree(Tree tree) { 73 trees.clear(); 74 addTree(tree); 75 showTree(0); 76 } 77 setTrees(Collection<? extends Tree> trees)78 public void setTrees(Collection<? extends Tree> trees) { 79 this.trees.clear(); 80 for (Tree tree : trees) { 81 addTree(tree); 82 } 83 showTree(0); 84 } 85 addTree(Tree tree)86 protected void addTree(Tree tree) { 87 this.trees.add(tree); 88 showTree(trees.size() - 1); 89 } 90 addTrees(Collection<? extends Tree> trees)91 public void addTrees(Collection<? extends Tree> trees) { 92 int count = getTreeCount(); 93 for (Tree tree : trees) { 94 addTree(tree); 95 } 96 showTree(count); 97 } 98 getTree()99 public Tree getTree() { 100 return trees.get(0); 101 } 102 getTrees()103 public java.util.List<Tree> getTrees() { 104 return trees; 105 } 106 getTreesPerPage()107 public int getTreesPerPage() { 108 return treesPerPage; 109 } 110 setTreesPerPage(int treesPerPage)111 public void setTreesPerPage(int treesPerPage) { 112 this.treesPerPage = treesPerPage; 113 if (treePanes.size() < treesPerPage) { 114 while (treePanes.size() < treesPerPage) { 115 treePanes.add(new TreePane()); 116 } 117 } else if (treePanes.size() > treesPerPage) { 118 while (treePanes.size() > treesPerPage) { 119 treePanes.remove(treePanes.size() - 1); 120 } 121 } 122 showTree(currentTreeIndex); 123 } 124 setupTreePane(TreePane treePane)125 private void setupTreePane(TreePane treePane) { 126 treePane.setAutoscrolls(true); //enable synthetic drag events 127 128 // This overrides MouseListener and MouseMotionListener to allow selection in the TreePane - 129 // It installs itself within the constructor. 130 treePaneSelector = new TreePaneSelector(treePane); 131 } 132 getCurrentTree()133 public Tree getCurrentTree() { 134 return trees.get(currentTreeIndex); 135 } 136 137 getCurrentTreeIndex()138 public int getCurrentTreeIndex() { 139 return currentTreeIndex; 140 } 141 getTreeCount()142 public int getTreeCount() { 143 if (trees == null) return 0; 144 return trees.size(); 145 } 146 getStatusProvider()147 public StatusProvider getStatusProvider() { 148 return null; 149 } 150 showTree(int index)151 public void showTree(int index) { 152 int i = index; 153 for (TreePane treePane : treePanes) { 154 if (i < trees.size()) { 155 Tree tree = trees.get(i); 156 157 if (tree instanceof RootedTree) { 158 treePane.setTree((RootedTree)tree); 159 } else { 160 treePane.setTree(Utils.rootTheTree(tree)); 161 } 162 } else { 163 treePane.setTree(null); 164 } 165 i++; 166 } 167 currentTreeIndex = index; 168 169 treePanePanel.removeAll(); 170 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 171 for (TreePane treePane : treePanes) { 172 treePanePanel.add(treePane); 173 setupTreePane(treePane); 174 } 175 176 fireTreeChanged(); 177 } 178 showNextTree()179 public void showNextTree() { 180 if (currentTreeIndex < trees.size() - 1) { 181 showTree(currentTreeIndex + 1); 182 } 183 } 184 showPreviousTree()185 public void showPreviousTree() { 186 if (currentTreeIndex > 0) { 187 showTree(currentTreeIndex - 1); 188 } 189 } 190 setTreeLayout(TreeLayout treeLayout)191 public void setTreeLayout(TreeLayout treeLayout) { 192 for (TreePane treePane : treePanes) { 193 treePane.setTreeLayout(treeLayout); 194 } 195 } 196 197 private boolean zoomPending = false; 198 private double zoom = 0.0, verticalExpansion = 0.0; 199 setZoom(double zoom)200 public void setZoom(double zoom) { 201 this.zoom = zoom * MAX_ZOOM; 202 refreshZoom(); 203 } 204 setVerticalExpansion(double verticalExpansion)205 public void setVerticalExpansion(double verticalExpansion) { 206 this.verticalExpansion = verticalExpansion * MAX_VERTICAL_EXPANSION; 207 refreshZoom(); 208 } 209 verticalExpansionAllowed()210 public boolean verticalExpansionAllowed() { 211 return !treePanes.get(0).maintainAspectRatio(); 212 } 213 setTimeScale(TimeScale timeScale)214 public void setTimeScale(TimeScale timeScale) { 215 for (TreePane treePane : treePanes) { 216 treePane.setTimeScale(timeScale); 217 } 218 } 219 refreshZoom()220 private void refreshZoom() { 221 setZoom(zoom, zoom + verticalExpansion); 222 } 223 setZoom(double xZoom, double yZoom)224 private void setZoom(double xZoom, double yZoom) { 225 226 Dimension viewportSize = viewport.getViewSize(); 227 Point position = viewport.getViewPosition(); 228 229 Dimension extentSize = viewport.getExtentSize(); 230 double w = extentSize.getWidth() * (1.0 + xZoom); 231 double h = extentSize.getHeight() * (1.0 + yZoom); 232 233 Dimension newSize = new Dimension((int) w, (int) h / treesPerPage); 234 for (TreePane treePane : treePanes) { 235 treePane.setPreferredSize(newSize); 236 treePane.revalidate(); 237 } 238 239 double cx = position.getX() + (0.5 * extentSize.getWidth()); 240 double cy = position.getY() + (0.5 * extentSize.getHeight()); 241 242 double rx = ((double) newSize.getWidth()) / viewportSize.getWidth(); 243 double ry = ((double) newSize.getHeight()) / viewportSize.getHeight(); 244 245 double px = (cx * rx) - (extentSize.getWidth() / 2.0); 246 double py = (cy * ry) - (extentSize.getHeight() / 2.0); 247 248 Point newPosition = new Point((int) px, (int) py); 249 viewport.setViewPosition(newPosition); 250 } 251 hasSelection()252 public boolean hasSelection() { 253 for (TreePane treePane : treePanes) { 254 if (treePane.hasSelection()) return true; 255 } 256 return false; 257 } 258 getSelectedNodes()259 public Set<Node> getSelectedNodes() { 260 for (TreePane treePane : treePanes) { 261 if (treePane.hasSelection()) return treePane.getSelectedNodes(); 262 } 263 return Collections.emptySet(); 264 } 265 getSelectedTips()266 public Set<Node> getSelectedTips() { 267 for (TreePane treePane : treePanes) { 268 if (treePane.hasSelection()) return treePane.getSelectedTips(); 269 } 270 return Collections.emptySet(); 271 } 272 selectTaxa(String attributeName, TextSearchType searchType, String searchString, boolean caseSensitive)273 public void selectTaxa(String attributeName, TextSearchType searchType, String searchString, boolean caseSensitive) { 274 } 275 selectNodes(String attribute, TextSearchType searchType, String searchString, boolean caseSensitive)276 public void selectNodes(String attribute, TextSearchType searchType, String searchString, boolean caseSensitive) { 277 } 278 selectTaxa(String attributeName, NumberSearchType searchType, Number searchValue)279 public void selectTaxa(String attributeName, NumberSearchType searchType, Number searchValue) { 280 } 281 selectNodes(String attributeName, NumberSearchType searchType, Number searchValue)282 public void selectNodes(String attributeName, NumberSearchType searchType, Number searchValue) { 283 } 284 selectTaxa(final Collection<String> taxonNames)285 public void selectTaxa(final Collection<String> taxonNames) { 286 } 287 collapseSelectedNodes()288 public void collapseSelectedNodes() { 289 // treePane.collapseSelectedNodes(); 290 } 291 annotateSelectedNodes(String name, Object value)292 public void annotateSelectedNodes(String name, Object value) { 293 // treePane.annotateSelectedNodes(name, value); 294 fireTreeSettingsChanged(); 295 } 296 annotateSelectedTips(String name, Object value)297 public void annotateSelectedTips(String name, Object value) { 298 // treePane.annotateSelectedTips(name, value); 299 fireTreeSettingsChanged(); 300 } 301 selectAll()302 public void selectAll() { 303 // if (treePaneSelector.getSelectionMode() == TreePaneSelector.SelectionMode.TAXA) { 304 // treePane.selectAllTaxa(); 305 // } else { 306 // treePane.selectAllNodes(); 307 // } 308 } 309 clearSelectedTaxa()310 public void clearSelectedTaxa() { 311 // treePane.clearSelection(); 312 } 313 addTreeSelectionListener(TreeSelectionListener treeSelectionListener)314 public void addTreeSelectionListener(TreeSelectionListener treeSelectionListener) { 315 for (TreePane treePane : treePanes) { 316 treePane.addTreeSelectionListener(treeSelectionListener); 317 } 318 } 319 removeTreeSelectionListener(TreeSelectionListener treeSelectionListener)320 public void removeTreeSelectionListener(TreeSelectionListener treeSelectionListener) { 321 for (TreePane treePane : treePanes) { 322 treePane.removeTreeSelectionListener(treeSelectionListener); 323 } 324 } 325 setSelectionMode(TreePaneSelector.SelectionMode selectionMode)326 public void setSelectionMode(TreePaneSelector.SelectionMode selectionMode) { 327 // TreePaneSelector.SelectionMode oldSelectionMode = treePaneSelector.getSelectionMode(); 328 // 329 // if (selectionMode == oldSelectionMode) { 330 // return; 331 // } 332 // 333 // if (oldSelectionMode == TreePaneSelector.SelectionMode.TAXA) { 334 // treePane.selectNodesFromSelectedTips(); 335 // } else if (selectionMode == TreePaneSelector.SelectionMode.TAXA) { 336 // treePane.selectTipsFromSelectedNodes(); 337 // } else if (selectionMode == TreePaneSelector.SelectionMode.CLADE) { 338 // treePane.selectCladesFromSelectedNodes(); 339 // } 340 // treePaneSelector.setSelectionMode(selectionMode); 341 } 342 setDragMode(TreePaneSelector.DragMode dragMode)343 public void setDragMode(TreePaneSelector.DragMode dragMode) { 344 treePaneSelector.setDragMode(dragMode); 345 } 346 347 // A load of deligated method calls through to treePane (which is now hidden outside the package). setTipLabelPainter(LabelPainter<Node> tipLabelPainter)348 public void setTipLabelPainter(LabelPainter<Node> tipLabelPainter) { 349 for (TreePane treePane : treePanes) { 350 treePane.setTipLabelPainter(tipLabelPainter); 351 } 352 // tipLabelPainter.setupAttributes(trees); 353 fireTreeSettingsChanged(); 354 } 355 setNodeLabelPainter(LabelPainter<Node> nodeLabelPainter)356 public void setNodeLabelPainter(LabelPainter<Node> nodeLabelPainter) { 357 for (TreePane treePane : treePanes) { 358 treePane.setNodeLabelPainter(nodeLabelPainter); 359 } 360 // nodeLabelPainter.setupAttributes(trees); 361 fireTreeSettingsChanged(); 362 } 363 setNodeBarPainter(NodeBarPainter nodeBarPainter)364 public void setNodeBarPainter(NodeBarPainter nodeBarPainter) { 365 for (TreePane treePane : treePanes) { 366 treePane.setNodeBarPainter(nodeBarPainter); 367 } 368 // nodeBarPainter.setupAttributes(trees); 369 fireTreeSettingsChanged(); 370 } 371 setNodeShapePainter(NodeShapePainter nodeShapePainter)372 public void setNodeShapePainter(NodeShapePainter nodeShapePainter) { 373 for (TreePane treePane : treePanes) { 374 treePane.setNodeShapePainter(nodeShapePainter); 375 } 376 fireTreeSettingsChanged(); 377 } 378 setBranchLabelPainter(LabelPainter<Node> branchLabelPainter)379 public void setBranchLabelPainter(LabelPainter<Node> branchLabelPainter) { 380 for (TreePane treePane : treePanes) { 381 treePane.setBranchLabelPainter(branchLabelPainter); 382 } 383 fireTreeSettingsChanged(); 384 } 385 addScalePainter(ScalePainter scalePainter)386 public void addScalePainter(ScalePainter scalePainter) { 387 for (TreePane treePane : treePanes) { 388 treePane.addScalePainter(scalePainter); 389 } 390 fireTreeSettingsChanged(); 391 } 392 removeScalePainter(ScalePainter scalePainter)393 public void removeScalePainter(ScalePainter scalePainter) { 394 for (TreePane treePane : treePanes) { 395 treePane.removeScalePainter(scalePainter); 396 } 397 fireTreeSettingsChanged(); 398 } 399 setScaleGridPainter(ScaleGridPainter scaleGridPainter)400 public void setScaleGridPainter(ScaleGridPainter scaleGridPainter) { 401 for (TreePane treePane : treePanes) { 402 treePane.setScaleGridPainter(scaleGridPainter); 403 } 404 fireTreeSettingsChanged(); 405 } 406 setLegendPainter(LegendPainter legendPainter)407 public void setLegendPainter(LegendPainter legendPainter) { 408 for (TreePane treePane : treePanes) { 409 treePane.setLegendPainter(legendPainter); 410 } 411 // legendPainter.setupAttributes(trees); 412 fireTreeSettingsChanged(); 413 } 414 setBranchDecorator(Decorator branchDecorator, boolean isGradient)415 public void setBranchDecorator(Decorator branchDecorator, boolean isGradient) { 416 for (TreePane treePane : treePanes) { 417 treePane.setBranchDecorator(branchDecorator, isGradient); 418 } 419 fireTreeSettingsChanged(); 420 } 421 setBranchColouringDecorator(String branchColouringAttribute, Decorator branchColouringDecorator)422 public void setBranchColouringDecorator(String branchColouringAttribute, Decorator branchColouringDecorator) { 423 for (TreePane treePane : treePanes) { 424 treePane.setBranchColouringDecorator(branchColouringAttribute, branchColouringDecorator); 425 } 426 fireTreeSettingsChanged(); 427 } 428 setNodeBackgroundDecorator(Decorator nodeBackgroundDecorator)429 public void setNodeBackgroundDecorator(Decorator nodeBackgroundDecorator) { 430 for (TreePane treePane : treePanes) { 431 treePane.setNodeBackgroundDecorator(nodeBackgroundDecorator); 432 } 433 fireTreeSettingsChanged(); 434 } 435 setHilightingGradient(boolean hilightingGradient)436 public void setHilightingGradient(boolean hilightingGradient) { 437 for (TreePane treePane : treePanes) { 438 treePane.setHilightingGradient(hilightingGradient); 439 } 440 } 441 setSelectionColor(Color selectionColor)442 public void setSelectionColor(Color selectionColor) { 443 for (TreePane treePane : treePanes) { 444 treePane.setSelectionColor(selectionColor); 445 } 446 fireTreeSettingsChanged(); 447 } 448 getSelectionPaint()449 public Paint getSelectionPaint() { 450 return treePanes.get(0).getSelectionPaint(); 451 } 452 setBranchStroke(BasicStroke branchStroke)453 public void setBranchStroke(BasicStroke branchStroke) { 454 for (TreePane treePane : treePanes) { 455 treePane.setBranchStroke(branchStroke); 456 } 457 fireTreeSettingsChanged(); 458 } 459 isTransformBranchesOn()460 public boolean isTransformBranchesOn() { 461 return treePanes.get(0).isTransformBranchesOn(); 462 } 463 getBranchTransform()464 public TransformedRootedTree.Transform getBranchTransform() { 465 return treePanes.get(0).getBranchTransform(); 466 } 467 setTransformBranchesOn(boolean transformBranchesOn)468 public void setTransformBranchesOn(boolean transformBranchesOn) { 469 for (TreePane treePane : treePanes) { 470 treePane.setTransformBranchesOn(transformBranchesOn); 471 } 472 fireTreeSettingsChanged(); 473 } 474 setBranchTransform(TransformedRootedTree.Transform transform)475 public void setBranchTransform(TransformedRootedTree.Transform transform) { 476 for (TreePane treePane : treePanes) { 477 treePane.setBranchTransform(transform); 478 } 479 fireTreeSettingsChanged(); 480 } 481 isOrderBranchesOn()482 public boolean isOrderBranchesOn() { 483 return treePanes.get(0).isOrderBranchesOn(); 484 } 485 getBranchOrdering()486 public SortedRootedTree.BranchOrdering getBranchOrdering() { 487 return treePanes.get(0).getBranchOrdering(); 488 } 489 setOrderBranchesOn(boolean orderBranchesOn)490 public void setOrderBranchesOn(boolean orderBranchesOn) { 491 for (TreePane treePane : treePanes) { 492 treePane.setOrderBranchesOn(orderBranchesOn); 493 } 494 fireTreeSettingsChanged(); 495 } 496 setBranchOrdering(SortedRootedTree.BranchOrdering branchOrdering)497 public void setBranchOrdering(SortedRootedTree.BranchOrdering branchOrdering) { 498 for (TreePane treePane : treePanes) { 499 treePane.setBranchOrdering(branchOrdering); 500 } 501 fireTreeSettingsChanged(); 502 } 503 isRootingOn()504 public boolean isRootingOn() { 505 return treePanes.get(0).isOrderBranchesOn(); 506 } 507 getRootingType()508 public TreePane.RootingType getRootingType() { 509 return treePanes.get(0).getRootingType(); 510 } 511 setRootingOn(boolean rootingOn)512 public void setRootingOn(boolean rootingOn) { 513 for (TreePane treePane : treePanes) { 514 treePane.setRootingOn(rootingOn); 515 } 516 fireTreeSettingsChanged(); 517 } 518 setRootingType(TreePane.RootingType rootingType)519 public void setRootingType(TreePane.RootingType rootingType) { 520 for (TreePane treePane : treePanes) { 521 treePane.setRootingType(rootingType); 522 } 523 fireTreeSettingsChanged(); 524 } 525 getContentPane()526 public JComponent getContentPane() { 527 return treePanePanel; 528 } 529 paint(Graphics g)530 public void paint(Graphics g) { 531 if( zoomPending ) { 532 refreshZoom(); 533 zoomPending = false; 534 } 535 super.paint(g); 536 } 537 print(Graphics g, PageFormat pageFormat, int pageIndex)538 public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException { 539 return treePanePanel.print(g, pageFormat, pageIndex); 540 } 541 addTreeViewerListener(TreeViewerListener listener)542 public void addTreeViewerListener(TreeViewerListener listener) { 543 listeners.add(listener); 544 } 545 removeTreeViewerListener(TreeViewerListener listener)546 public void removeTreeViewerListener(TreeViewerListener listener) { 547 listeners.remove(listener); 548 } 549 fireTreeChanged()550 public void fireTreeChanged() { 551 for (TreeViewerListener listener : listeners) { 552 listener.treeChanged(); 553 } 554 } 555 fireTreeSettingsChanged()556 public void fireTreeSettingsChanged() { 557 for (TreeViewerListener listener : listeners) { 558 listener.treeSettingsChanged(); 559 } 560 } 561 562 private java.util.List<TreeViewerListener> listeners = new ArrayList<TreeViewerListener>(); 563 564 private java.util.List<Tree> trees = new ArrayList<Tree>(); 565 private java.util.List<TreePane> treePanes = new ArrayList<TreePane>(); 566 private int currentTreeIndex = 0; 567 private int treesPerPage = 1; 568 569 private MultiPaneTreePanel treePanePanel; 570 protected TreePaneSelector treePaneSelector; 571 protected JViewport viewport; 572 573 class MultiPaneTreePanel extends JPanel implements Printable { 574 print(Graphics graphics, PageFormat pageFormat, int i)575 public int print(Graphics graphics, PageFormat pageFormat, int i) throws PrinterException { 576 return 0; 577 } 578 } 579 } 580