/** * Copyright (c) 2009, iPlant Collaborative, Texas Advanced Computing Center This software is licensed * under the CC-GNU GPL version 2.0 or later. License: http://creativecommons.org/licenses/GPL/2.0/ */ package org.iplantc.phyloviewer.shared.render; import java.util.Stack; import org.iplantc.phyloviewer.shared.layout.ILayoutData; import org.iplantc.phyloviewer.shared.math.Box2D; import org.iplantc.phyloviewer.shared.math.Matrix33; import org.iplantc.phyloviewer.shared.model.IDocument; import org.iplantc.phyloviewer.shared.model.INode; import org.iplantc.phyloviewer.shared.model.ITree; import org.iplantc.phyloviewer.shared.render.style.CompositeStyle; import org.iplantc.phyloviewer.shared.render.style.IStyle; import org.iplantc.phyloviewer.shared.scene.Drawable; import org.iplantc.phyloviewer.shared.scene.DrawableContainer; import org.iplantc.phyloviewer.shared.scene.IDrawableBuilder; import org.iplantc.phyloviewer.shared.scene.ILODSelector; import org.iplantc.phyloviewer.shared.scene.ILODSelector.LODLevel; public abstract class RenderTree { private RenderPreferences renderPreferences = new RenderPreferences(); IDocument document; IDrawableBuilder builder; ILODSelector lodSelector; DrawableContainer drawableContainer = new DrawableContainer(); Stack<Boolean> highlightSubTreeStack = new Stack<Boolean>(); public RenderTree() { } public IDocument getDocument() { return document; } public void setDocument(IDocument document) { this.document = document; drawableContainer.clear(); } protected void setDrawableBuilder(IDrawableBuilder builder) { this.builder = builder; drawableContainer.setBuilder(builder); } protected void setLODSelector(ILODSelector lodSelector) { this.lodSelector = lodSelector; } public DrawableContainer getDrawableContainer() { return drawableContainer; } public void renderTree(IGraphics graphics, Matrix33 viewMatrix) { ITree tree = document != null ? document.getTree() : null; ILayoutData layout = document != null ? document.getLayout() : null; if(document == null || tree == null || graphics == null || layout == null || builder == null || lodSelector == null) return; INode root = tree.getRootNode(); if(root == null) return; if(viewMatrix != null) { graphics.setViewMatrix(viewMatrix); } graphics.clear(); highlightSubTreeStack.clear(); highlightSubTreeStack.push(false); this.renderNode(root, layout, graphics); } public RenderPreferences getRenderPreferences() { return renderPreferences; } public void setRenderPreferences(RenderPreferences preferences) { renderPreferences = preferences; } protected void renderNode(INode node, ILayoutData layout, IGraphics graphics) { if(graphics.isCulled(this.getBoundingBox(node, layout))) { return; } boolean stackNeedsPopped = false; if(renderPreferences.isSubTreeHighlighted(node)) { highlightSubTreeStack.push(true); stackNeedsPopped = true; } if(renderPreferences.drawLabels() && node.isLeaf()) { drawLabel(node, layout, graphics); } else if(renderPreferences.isCollapsed(node) || (renderPreferences.collapseOverlaps() && LODLevel.LOD_LOW == lodSelector.getLODLevel( node, layout, graphics.getObjectToScreenMatrix()))) { renderPlaceholder(node, layout, graphics); } else if(!document.checkForData(node)) { // while checkForData gets children and layouts (async), render a subtree placeholder renderPlaceholder(node, layout, graphics); } else { renderChildren(node, layout, graphics); } if(renderPreferences.isDrawPoints()) { boolean isHighlighted = renderPreferences.isNodeHighlighted(node); IStyle style = this.getStyle(node, isHighlighted); Drawable[] drawables = drawableContainer.getNodeDrawables(node, document, layout); for(Drawable drawable : drawables) { drawable.draw(graphics, style); } } if(stackNeedsPopped) { highlightSubTreeStack.pop(); } } public Box2D getBoundingBox(INode node, ILayoutData layout) { return layout.getBoundingBox(node); } protected void drawLabel(INode node, ILayoutData layout, IGraphics graphics) { IStyle style = this.getStyle(node, false); Drawable drawable = drawableContainer.getTextDrawable(node, document, layout); drawable.draw(graphics, style); } protected void renderChildren(INode parent, ILayoutData layout, IGraphics graphics) { INode[] children = parent.getChildren(); for(int i = 0;i < children.length;++i) { INode child = children[i]; boolean isHighlighted = renderPreferences.isBranchHighlighted(child); IStyle style = this.getStyle(child, isHighlighted); Drawable[] drawables = drawableContainer.getBranchDrawables(parent, child, document, layout); for(Drawable drawable : drawables) { drawable.draw(graphics, style); } renderNode(child, layout, graphics); } } protected void renderPlaceholder(INode node, ILayoutData layout, IGraphics graphics) { IStyle style = this.getStyle(node, false); Drawable[] drawables = drawableContainer.getGlyphDrawables(node, document, layout); for(Drawable drawable : drawables) { drawable.draw(graphics, style); } } /** * If the node has been highlighted, the returned style will be renderPreferences.getHighlightStyle() * composited with the node style * * @see CompositeStyle */ protected IStyle getStyle(INode node, boolean isHighlighted) { assert (document != null); IStyle style = document.getStyle(node); if(isHighlighted || highlightSubTreeStack.peek()) { CompositeStyle highlightStyle = renderPreferences.getHighlightStyle(); if(highlightStyle != null) { highlightStyle.setBaseStyle(style); style = highlightStyle; } } return style; } }