/******************************************************************************* * Copyright (c) 2007, 2008 Gregory Jordan * * This file is part of PhyloWidget. * * PhyloWidget 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. * * PhyloWidget 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 * PhyloWidget. If not, see <http://www.gnu.org/licenses/>. */ package org.phylowidget; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import org.andrewberman.ui.AbstractUIObject; import org.andrewberman.ui.UIRectangle; import org.andrewberman.ui.camera.RectMover; import org.andrewberman.ui.unsorted.MethodAndFieldSetter; import org.jgrapht.event.GraphChangeEvent; import org.jgrapht.event.GraphEdgeChangeEvent; import org.jgrapht.event.GraphListener; import org.jgrapht.event.GraphVertexChangeEvent; import org.phylowidget.render.BasicTreeRenderer; import org.phylowidget.render.LayoutCircular; import org.phylowidget.render.LayoutCladogram; import org.phylowidget.render.LayoutDiagonal; import org.phylowidget.render.LayoutUnrooted; import org.phylowidget.render.images.ImageLoader; import org.phylowidget.tree.PhyloNode; import org.phylowidget.tree.RootedTree; import org.phylowidget.tree.TreeIO; import org.phylowidget.ui.PhyloScaleBar; import processing.core.PApplet; public class TreeManager extends AbstractUIObject implements GraphListener { protected PApplet p; protected PWContext context; public static RectMover camera; public static UIRectangle cameraRect; // protected ArrayList trees; // protected ArrayList renderers; public static ImageLoader imageLoader; BasicTreeRenderer r; RootedTree t; // public Navigator nav; private RandomTreeMutator mutator; private boolean mutateMe; private Runnable runMe; private boolean fforwardMe; private PhyloScaleBar scaleBar; public TreeManager(PApplet p) { this.p = p; this.context = PWPlatform.getInstance().getThisAppContext(); context.event().add(this); } public void setup() { imageLoader = new ImageLoader(); cameraRect = new UIRectangle(0, 0, 0, 0); camera = new RectMover(p); fillScreen(); camera.nudgeTo(-context.config().viewportX, -context.config().viewportY); camera.zoomTo(context.config().viewportZoom); camera.fforward(); /* * We need to let the ToolManager know our current Camera object. */ context.event().setCamera(camera); setTree(TreeIO.parseNewickString(new PhyloTree(), context.config().tree)); setRenderer(new BasicTreeRenderer(context)); context.config().setLayout(context.config().layout); context.config().setFont(context.config().font); fireCallback(); if (context.config().showScaleBar) scaleBar = new PhyloScaleBar(p); } public void showScaleBar() { if (scaleBar == null) scaleBar = new PhyloScaleBar(p); } public void hideScaleBar() { if (scaleBar != null) { scaleBar.dispose(); scaleBar = null; } } public void draw() { update(); } protected void updateCameraRect() { cameraRect.setRect(camera.getRect()); cameraRect.translate(p.width / 2, p.height / 2); } public void update() { if (camera != null && r != null) { camera.update(); updateCameraRect(); r.render(p.g, cameraRect.x, cameraRect.y, cameraRect.width, cameraRect.height, true); context.config().viewportX = -camera.getX(); context.config().viewportY = -camera.getY(); if (context.config().viewportX == 0); context.config().viewportX = 0.0f; if (context.config().viewportY == 0); context.config().viewportY = 0.0f; context.config().viewportZoom = camera.getZ(); } if (mutateMe) { mutator.randomlyMutateTree(); mutateMe = false; } // Synchronize with the PhyloConfig values. // if (runMe != null) // { // Runnable r = runMe; // runMe = null; // r.run(); // } } public void nodesInRange(ArrayList list, Rectangle2D.Float rect) { r.nodesInRange(list, rect); } // public void nodesTouchingPoint(ArrayList list, Point2D.Float pt) // { // Rectangle2D.Float rect = new Rectangle2D.Float(); // rect.setFrame(pt.x, pt.y, 0, 0); // nodesInRange(list, rect); // } public void mutateTree() { // mutator.randomlyMutateTree(); mutateMe = true; } public void startMutatingTree(int delay) { mutator.stop(); mutator = new RandomTreeMutator(t); mutator.setDelay(delay); mutator.start(); } public void stopMutatingTree() { mutator.stop(); } public synchronized RootedTree getTree() { return t; } public BasicTreeRenderer getRenderer() { return r; } public synchronized void setTree(String s) { if (getTree() != null) { TreeIO.setOldTree(getTree()); } setTree(TreeIO.parseNewickString(new PhyloTree(), s)); } private void setConfigParametersFromTree() { if (getTree() != null) { PhyloNode n = (PhyloNode) getTree().getRoot(); if (n != null && context.config() != null && n.getAnnotations() != null) { MethodAndFieldSetter.setMethodsAndFields(context.config(), n.getAnnotations()); } } } public void setTree(final RootedTree tree) { if (t != null) { /* * Whenever doing something to the tree (such as DISPOSING it!) we need to lock * on it, because the renderer (which is on a different thread) could be using it at the moment. */ synchronized (t) { t.removeGraphListener(this); t.dispose(); t = null; } } this.t = tree; tree.addGraphListener(this); if (getRenderer() != null) { getRenderer().setTree(tree); } if (tree instanceof PhyloTree) { PhyloTree pt = (PhyloTree) tree; } fforwardMe = true; mutator = new RandomTreeMutator(tree); setConfigParametersFromTree(); } public synchronized void diagonalRender() { // setRenderer(new DiagonalCladogram()); getRenderer().setLayout(new LayoutDiagonal()); } public synchronized void rectangleRender() { // setRenderer(new BasicTreeRenderer()); getRenderer().setLayout(new LayoutCladogram()); } public synchronized void circleRender() { // setRenderer(new Circlegram()); getRenderer().setLayout(new LayoutCircular()); } public synchronized void unrootedRender() { getRenderer().setLayout(new LayoutUnrooted()); } synchronized void setRenderer(BasicTreeRenderer r) { if (getRenderer() != null) { synchronized (this.r) { getRenderer().dispose(); } } this.r = r; if (getTree() != null) r.setTree(getTree()); context.ui().search(); } public void triggerMutation() { mutateMe = true; } // public UIRectangle getVisibleRect() // { // UIRectangle fl = getRenderer().getVisibleRect(); // fl.translate(-p.width / 2, -p.height / 2); // return fl; // } public void destroy() { if (r != null) r.dispose(); r = null; if (t != null) t.dispose(); t = null; p = null; camera = null; cameraRect = null; if (imageLoader != null) imageLoader.dispose(); imageLoader = null; } public void fillScreen() { camera.fillScreen(0.7f); } public final static int TREE_CHANGE_EVENT = 81294187; private void treeChanged(GraphChangeEvent e) { fireEvent(TREE_CHANGE_EVENT); } public void fireCallback() { fireEvent(TREE_CHANGE_EVENT); } public void edgeAdded(GraphEdgeChangeEvent e) { // treeChanged(e); } public void edgeRemoved(GraphEdgeChangeEvent e) { // treeChanged(e); } public void vertexAdded(GraphVertexChangeEvent e) { treeChanged(e); } public void vertexRemoved(GraphVertexChangeEvent e) { treeChanged(e); } }