/******************************************************************************* * Copyright (c) 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.draw2d.examples.tree; import java.util.List; import org.eclipse.draw2d.ColorConstants; import org.eclipse.draw2d.Figure; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Layer; import org.eclipse.draw2d.LineBorder; import org.eclipse.draw2d.PositionConstants; import org.eclipse.draw2d.ToolbarLayout; import org.eclipse.draw2d.Viewport; import org.eclipse.draw2d.geometry.Dimension; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; /** * @author hudsonr * Created on Apr 21, 2003 */ public class TreeBranch extends Figure { class AnimatingLayer extends Layer { /** * @see org.eclipse.draw2d.Figure#setBounds(org.eclipse.draw2d.geometry.Rectangle) */ public void setBounds(Rectangle rect) { int x = bounds.x, y = bounds.y; boolean resize = (rect.width != bounds.width) || (rect.height != bounds.height), translate = (rect.x != x) || (rect.y != y); if (isVisible() && (resize || translate)) erase(); if (translate) { int dx = rect.x - x; int dy = rect.y - y; primTranslate(dx, dy); } bounds.width = rect.width; bounds.height = rect.height; // if (resize) Layouts dont depend on size. // invalidate(); if (resize || translate) { fireMoved(); repaint(); } } } public static final int STYLE_HANGING = 1; public static final int STYLE_NORMAL = 2; int aligment = PositionConstants.CENTER; /* * A layer is being used simply because it is the only "transparent" figure in draw2d. See * the implementation of Layer.containsPoint(...) for what is meant by "transparent". If a * layer is not used, then overlapping branches will cause hit-test problems. */ AnimatingLayer contents = new AnimatingLayer(); boolean expanded = true; IFigure node; int style; public TreeBranch(IFigure title) { this(title, STYLE_NORMAL); } public TreeBranch(IFigure title, int style) { setStyle(style); if (title.getBorder() == null) title.setBorder(new LineBorder(ColorConstants.gray(), 2)); this.node = title; add(contents); add(title); } /** * recursively set all nodes and sub-treebranch nodes to the same location. This gives * the appearance of all nodes coming from the same place. * @param bounds where to set */ public void animationReset(Rectangle bounds) { List subtrees = contents.getChildren(); contents.setBounds(bounds); //Make the center of this node match the center of the given bounds Rectangle r = node.getBounds(); int dx = bounds.x + bounds.width / 2 - r.x - r.width/2; int dy = bounds.y + bounds.height/ 2 - r.y - r.height/2; node.translate(dx, dy); revalidate(); //Otherwise, this branch will not layout //Pass the location to all children for (int i=0; i<subtrees.size(); i++){ TreeBranch subtree = (TreeBranch)subtrees.get(i); subtree.setBounds(bounds); subtree.animationReset(bounds); } } public void collapse() { if (!expanded) return; IFigure root = this; Viewport port = null; Point viewportStart = null; while (root.getParent() != null) { if (root instanceof Viewport) port = ((Viewport)root); root = root.getParent(); } viewportStart = port.getViewLocation(); Point nodeStart = node.getBounds().getLocation(); setExpanded(false); root.validate(); setExpanded(true); animationReset(getNodeBounds()); Animation.mark(getNode()); Animation.captureLayout(getRoot()); Animation.swap(); Animation.trackLocation = nodeStart; root.validate(); port.setViewLocation(viewportStart); while(Animation.step()) getUpdateManager().performUpdate(); Animation.end(); setExpanded(false); } /** * @see org.eclipse.draw2d.Figure#containsPoint(int, int) */ public boolean containsPoint(int x, int y) { return node.containsPoint(x, y) || contents.containsPoint(x, y); } public void expand() { if (expanded) return; setExpanded(true); animationReset(getNodeBounds()); Animation.mark(getNode()); Animation.captureLayout(getRoot()); while(Animation.step()) getUpdateManager().performUpdate(); Animation.end(); } public int getAlignment() { return aligment; } protected BranchLayout getBranchLayout() { return (BranchLayout)getLayoutManager(); } public IFigure getContentsPane() { return contents; } public int[] getContourLeft() { return getBranchLayout().getContourLeft(); } public int[] getContourRight() { return getBranchLayout().getContourRight(); } public int getDepth() { return getBranchLayout().getDepth(); } /** * @see org.eclipse.draw2d.Figure#getMinimumSize(int, int) */ public Dimension getMinimumSize(int wHint, int hHint) { if (!Animation.PLAYBACK) validate(); return super.getMinimumSize(wHint, hHint); } public IFigure getNode() { return node; } public Rectangle getNodeBounds() { return node.getBounds(); } public int[] getPreferredRowHeights() { return getBranchLayout().getPreferredRowHeights(); } /** * @see org.eclipse.draw2d.Figure#getPreferredSize(int, int) */ public Dimension getPreferredSize(int wHint, int hHint) { if (!Animation.PLAYBACK) validate(); return super.getPreferredSize(wHint, hHint); } public TreeRoot getRoot() { return ((TreeBranch)getParent().getParent()).getRoot(); } public int getStyle() { return style; } /** * @return */ public boolean isExpanded() { return expanded; } /** * @see org.eclipse.draw2d.Figure#paintFigure(org.eclipse.draw2d.Graphics) */ protected void paintFigure(Graphics graphics) { super.paintFigure(graphics); if (isExpanded()) getBranchLayout().paintLines(graphics); // if (getDepth() == 2) // graphics.drawRectangle(getBounds().getResized(-1, -1)); } public void setAlignment(int value) { aligment = value; revalidate(); } /** * @param b */ public void setExpanded(boolean b) { if (expanded == b) return; expanded = b; contents.setVisible(b); revalidate(); } public void setNode(IFigure node) { remove(this.node); add(this.node, 0); } public void setRowHeights(int heights[], int offset) { getBranchLayout().setRowHeights(heights, offset); } public void setStyle(int style) { if (this.style == style) return; this.style = style; switch (style) { case STYLE_HANGING : setLayoutManager(new HangingLayout(this)); break; default : setLayoutManager(new NormalLayout(this)); contents.setLayoutManager(new TreeLayout()); break; } } /** * @see java.lang.Object#toString() */ public String toString() { return toString(0); } public String toString(int level) { String result = ""; for (int i=0; i<level; i++) result += " "; result += getChildren().get(1) + "\n"; for (int i=0; i<contents.getChildren().size(); i++) result += ((TreeBranch)contents.getChildren().get(i)).toString(level + 1); return result; } /** * @see org.eclipse.draw2d.Figure#validate() */ public void validate() { if (isValid()) return; if (style == STYLE_HANGING) { ToolbarLayout layout = new ToolbarLayout(!getRoot().isHorizontal()) { public void layout(IFigure parent) { Animation.recordInitialState(parent); if (Animation.playbackState(parent)) return; super.layout(parent); } }; layout.setMinorAlignment(ToolbarLayout.ALIGN_TOPLEFT); layout.setStretchMinorAxis(false); contents.setLayoutManager(layout); } repaint(); super.validate(); } }