/*
* 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;
}
}
}