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