/* * MultiPaneTreeViewer.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; import figtree.treeviewer.painters.*; import jebl.evolution.trees.*; import jebl.evolution.graphs.Node; import figtree.treeviewer.treelayouts.TreeLayout; import figtree.treeviewer.decorators.Decorator; import javax.swing.*; import java.awt.*; import java.awt.print.*; import java.util.*; import jam.panels.StatusProvider; /** * @author Andrew Rambaut * @version $Id$ * * $HeadURL$ * * $LastChangedBy$ * $LastChangedDate$ * $LastChangedRevision$ */ public class MultiPaneTreeViewer extends TreeViewer { private final static double MAX_ZOOM = 20; private final static double MAX_VERTICAL_EXPANSION = 20; /** * Creates new TreeViewer */ public MultiPaneTreeViewer() { treePanes.add(new TreePane()); setLayout(new BorderLayout()); treePanePanel = new MultiPaneTreePanel(); treePanePanel.setLayout(new BoxLayout(treePanePanel, BoxLayout.PAGE_AXIS)); JScrollPane scrollPane = new JScrollPane(treePanePanel, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); scrollPane.setMinimumSize(new Dimension(150, 150)); scrollPane.setBorder(null); viewport = scrollPane.getViewport(); add(scrollPane, BorderLayout.CENTER); } public void setTree(Tree tree) { trees.clear(); addTree(tree); showTree(0); } public void setTrees(Collection<? extends Tree> trees) { this.trees.clear(); for (Tree tree : trees) { addTree(tree); } showTree(0); } protected void addTree(Tree tree) { this.trees.add(tree); showTree(trees.size() - 1); } public void addTrees(Collection<? extends Tree> trees) { int count = getTreeCount(); for (Tree tree : trees) { addTree(tree); } showTree(count); } public Tree getTree() { return trees.get(0); } public java.util.List<Tree> getTrees() { return trees; } public int getTreesPerPage() { return treesPerPage; } public void setTreesPerPage(int treesPerPage) { this.treesPerPage = treesPerPage; if (treePanes.size() < treesPerPage) { while (treePanes.size() < treesPerPage) { treePanes.add(new TreePane()); } } else if (treePanes.size() > treesPerPage) { while (treePanes.size() > treesPerPage) { treePanes.remove(treePanes.size() - 1); } } showTree(currentTreeIndex); } private void setupTreePane(TreePane treePane) { treePane.setAutoscrolls(true); //enable synthetic drag events // This overrides MouseListener and MouseMotionListener to allow selection in the TreePane - // It installs itself within the constructor. treePaneSelector = new TreePaneSelector(treePane); } public Tree getCurrentTree() { return trees.get(currentTreeIndex); } public int getCurrentTreeIndex() { return currentTreeIndex; } public int getTreeCount() { if (trees == null) return 0; return trees.size(); } public StatusProvider getStatusProvider() { return null; } public void showTree(int index) { int i = index; for (TreePane treePane : treePanes) { if (i < trees.size()) { Tree tree = trees.get(i); if (tree instanceof RootedTree) { treePane.setTree((RootedTree)tree); } else { treePane.setTree(Utils.rootTheTree(tree)); } } else { treePane.setTree(null); } i++; } currentTreeIndex = index; treePanePanel.removeAll(); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); for (TreePane treePane : treePanes) { treePanePanel.add(treePane); setupTreePane(treePane); } fireTreeChanged(); } public void showNextTree() { if (currentTreeIndex < trees.size() - 1) { showTree(currentTreeIndex + 1); } } public void showPreviousTree() { if (currentTreeIndex > 0) { showTree(currentTreeIndex - 1); } } public void setTreeLayout(TreeLayout treeLayout) { for (TreePane treePane : treePanes) { treePane.setTreeLayout(treeLayout); } } private boolean zoomPending = false; private double zoom = 0.0, verticalExpansion = 0.0; public void setZoom(double zoom) { this.zoom = zoom * MAX_ZOOM; refreshZoom(); } public void setVerticalExpansion(double verticalExpansion) { this.verticalExpansion = verticalExpansion * MAX_VERTICAL_EXPANSION; refreshZoom(); } public boolean verticalExpansionAllowed() { return !treePanes.get(0).maintainAspectRatio(); } public void setTimeScale(TimeScale timeScale) { for (TreePane treePane : treePanes) { treePane.setTimeScale(timeScale); } } private void refreshZoom() { setZoom(zoom, zoom + verticalExpansion); } private void setZoom(double xZoom, double yZoom) { Dimension viewportSize = viewport.getViewSize(); Point position = viewport.getViewPosition(); Dimension extentSize = viewport.getExtentSize(); double w = extentSize.getWidth() * (1.0 + xZoom); double h = extentSize.getHeight() * (1.0 + yZoom); Dimension newSize = new Dimension((int) w, (int) h / treesPerPage); for (TreePane treePane : treePanes) { treePane.setPreferredSize(newSize); treePane.revalidate(); } double cx = position.getX() + (0.5 * extentSize.getWidth()); double cy = position.getY() + (0.5 * extentSize.getHeight()); double rx = ((double) newSize.getWidth()) / viewportSize.getWidth(); double ry = ((double) newSize.getHeight()) / viewportSize.getHeight(); double px = (cx * rx) - (extentSize.getWidth() / 2.0); double py = (cy * ry) - (extentSize.getHeight() / 2.0); Point newPosition = new Point((int) px, (int) py); viewport.setViewPosition(newPosition); } public boolean hasSelection() { for (TreePane treePane : treePanes) { if (treePane.hasSelection()) return true; } return false; } public Set<Node> getSelectedNodes() { for (TreePane treePane : treePanes) { if (treePane.hasSelection()) return treePane.getSelectedNodes(); } return Collections.emptySet(); } public Set<Node> getSelectedTips() { for (TreePane treePane : treePanes) { if (treePane.hasSelection()) return treePane.getSelectedTips(); } return Collections.emptySet(); } public void selectTaxa(String attributeName, TextSearchType searchType, String searchString, boolean caseSensitive) { } public void selectNodes(String attribute, TextSearchType searchType, String searchString, boolean caseSensitive) { } public void selectTaxa(String attributeName, NumberSearchType searchType, Number searchValue) { } public void selectNodes(String attributeName, NumberSearchType searchType, Number searchValue) { } public void selectTaxa(final Collection<String> taxonNames) { } public void collapseSelectedNodes() { // treePane.collapseSelectedNodes(); } public void annotateSelectedNodes(String name, Object value) { // treePane.annotateSelectedNodes(name, value); fireTreeSettingsChanged(); } public void annotateSelectedTips(String name, Object value) { // treePane.annotateSelectedTips(name, value); fireTreeSettingsChanged(); } public void selectAll() { // if (treePaneSelector.getSelectionMode() == TreePaneSelector.SelectionMode.TAXA) { // treePane.selectAllTaxa(); // } else { // treePane.selectAllNodes(); // } } public void clearSelectedTaxa() { // treePane.clearSelection(); } public void addTreeSelectionListener(TreeSelectionListener treeSelectionListener) { for (TreePane treePane : treePanes) { treePane.addTreeSelectionListener(treeSelectionListener); } } public void removeTreeSelectionListener(TreeSelectionListener treeSelectionListener) { for (TreePane treePane : treePanes) { treePane.removeTreeSelectionListener(treeSelectionListener); } } public void setSelectionMode(TreePaneSelector.SelectionMode selectionMode) { // TreePaneSelector.SelectionMode oldSelectionMode = treePaneSelector.getSelectionMode(); // // if (selectionMode == oldSelectionMode) { // return; // } // // if (oldSelectionMode == TreePaneSelector.SelectionMode.TAXA) { // treePane.selectNodesFromSelectedTips(); // } else if (selectionMode == TreePaneSelector.SelectionMode.TAXA) { // treePane.selectTipsFromSelectedNodes(); // } else if (selectionMode == TreePaneSelector.SelectionMode.CLADE) { // treePane.selectCladesFromSelectedNodes(); // } // treePaneSelector.setSelectionMode(selectionMode); } public void setDragMode(TreePaneSelector.DragMode dragMode) { treePaneSelector.setDragMode(dragMode); } // A load of deligated method calls through to treePane (which is now hidden outside the package). public void setTipLabelPainter(LabelPainter<Node> tipLabelPainter) { for (TreePane treePane : treePanes) { treePane.setTipLabelPainter(tipLabelPainter); } // tipLabelPainter.setupAttributes(trees); fireTreeSettingsChanged(); } public void setNodeLabelPainter(LabelPainter<Node> nodeLabelPainter) { for (TreePane treePane : treePanes) { treePane.setNodeLabelPainter(nodeLabelPainter); } // nodeLabelPainter.setupAttributes(trees); fireTreeSettingsChanged(); } public void setNodeBarPainter(NodeBarPainter nodeBarPainter) { for (TreePane treePane : treePanes) { treePane.setNodeBarPainter(nodeBarPainter); } // nodeBarPainter.setupAttributes(trees); fireTreeSettingsChanged(); } public void setNodeShapePainter(NodeShapePainter nodeShapePainter) { for (TreePane treePane : treePanes) { treePane.setNodeShapePainter(nodeShapePainter); } fireTreeSettingsChanged(); } public void setBranchLabelPainter(LabelPainter<Node> branchLabelPainter) { for (TreePane treePane : treePanes) { treePane.setBranchLabelPainter(branchLabelPainter); } fireTreeSettingsChanged(); } public void addScalePainter(ScalePainter scalePainter) { for (TreePane treePane : treePanes) { treePane.addScalePainter(scalePainter); } fireTreeSettingsChanged(); } public void removeScalePainter(ScalePainter scalePainter) { for (TreePane treePane : treePanes) { treePane.removeScalePainter(scalePainter); } fireTreeSettingsChanged(); } public void setScaleGridPainter(ScaleGridPainter scaleGridPainter) { for (TreePane treePane : treePanes) { treePane.setScaleGridPainter(scaleGridPainter); } fireTreeSettingsChanged(); } public void setLegendPainter(LegendPainter legendPainter) { for (TreePane treePane : treePanes) { treePane.setLegendPainter(legendPainter); } // legendPainter.setupAttributes(trees); fireTreeSettingsChanged(); } public void setBranchDecorator(Decorator branchDecorator, boolean isGradient) { for (TreePane treePane : treePanes) { treePane.setBranchDecorator(branchDecorator, isGradient); } fireTreeSettingsChanged(); } public void setBranchColouringDecorator(String branchColouringAttribute, Decorator branchColouringDecorator) { for (TreePane treePane : treePanes) { treePane.setBranchColouringDecorator(branchColouringAttribute, branchColouringDecorator); } fireTreeSettingsChanged(); } public void setNodeBackgroundDecorator(Decorator nodeBackgroundDecorator) { for (TreePane treePane : treePanes) { treePane.setNodeBackgroundDecorator(nodeBackgroundDecorator); } fireTreeSettingsChanged(); } public void setHilightingGradient(boolean hilightingGradient) { for (TreePane treePane : treePanes) { treePane.setHilightingGradient(hilightingGradient); } } public void setSelectionColor(Color selectionColor) { for (TreePane treePane : treePanes) { treePane.setSelectionColor(selectionColor); } fireTreeSettingsChanged(); } public Paint getSelectionPaint() { return treePanes.get(0).getSelectionPaint(); } public void setBranchStroke(BasicStroke branchStroke) { for (TreePane treePane : treePanes) { treePane.setBranchStroke(branchStroke); } fireTreeSettingsChanged(); } public boolean isTransformBranchesOn() { return treePanes.get(0).isTransformBranchesOn(); } public TransformedRootedTree.Transform getBranchTransform() { return treePanes.get(0).getBranchTransform(); } public void setTransformBranchesOn(boolean transformBranchesOn) { for (TreePane treePane : treePanes) { treePane.setTransformBranchesOn(transformBranchesOn); } fireTreeSettingsChanged(); } public void setBranchTransform(TransformedRootedTree.Transform transform) { for (TreePane treePane : treePanes) { treePane.setBranchTransform(transform); } fireTreeSettingsChanged(); } public boolean isOrderBranchesOn() { return treePanes.get(0).isOrderBranchesOn(); } public SortedRootedTree.BranchOrdering getBranchOrdering() { return treePanes.get(0).getBranchOrdering(); } public void setOrderBranchesOn(boolean orderBranchesOn) { for (TreePane treePane : treePanes) { treePane.setOrderBranchesOn(orderBranchesOn); } fireTreeSettingsChanged(); } public void setBranchOrdering(SortedRootedTree.BranchOrdering branchOrdering) { for (TreePane treePane : treePanes) { treePane.setBranchOrdering(branchOrdering); } fireTreeSettingsChanged(); } public boolean isRootingOn() { return treePanes.get(0).isOrderBranchesOn(); } public TreePane.RootingType getRootingType() { return treePanes.get(0).getRootingType(); } public void setRootingOn(boolean rootingOn) { for (TreePane treePane : treePanes) { treePane.setRootingOn(rootingOn); } fireTreeSettingsChanged(); } public void setRootingType(TreePane.RootingType rootingType) { for (TreePane treePane : treePanes) { treePane.setRootingType(rootingType); } fireTreeSettingsChanged(); } public JComponent getContentPane() { return treePanePanel; } public void paint(Graphics g) { if( zoomPending ) { refreshZoom(); zoomPending = false; } super.paint(g); } public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException { return treePanePanel.print(g, pageFormat, pageIndex); } public void addTreeViewerListener(TreeViewerListener listener) { listeners.add(listener); } public void removeTreeViewerListener(TreeViewerListener listener) { listeners.remove(listener); } public void fireTreeChanged() { for (TreeViewerListener listener : listeners) { listener.treeChanged(); } } public void fireTreeSettingsChanged() { for (TreeViewerListener listener : listeners) { listener.treeSettingsChanged(); } } private java.util.List<TreeViewerListener> listeners = new ArrayList<TreeViewerListener>(); private java.util.List<Tree> trees = new ArrayList<Tree>(); private java.util.List<TreePane> treePanes = new ArrayList<TreePane>(); private int currentTreeIndex = 0; private int treesPerPage = 1; private MultiPaneTreePanel treePanePanel; protected TreePaneSelector treePaneSelector; protected JViewport viewport; class MultiPaneTreePanel extends JPanel implements Printable { public int print(Graphics graphics, PageFormat pageFormat, int i) throws PrinterException { return 0; } } }