001: package visualdebugger.draw2d;
002:
003: import java.util.List;
004:
005: import org.eclipse.draw2d.AbstractLayout;
006: import org.eclipse.draw2d.IFigure;
007: import org.eclipse.draw2d.geometry.Dimension;
008: import org.eclipse.draw2d.geometry.Point;
009: import org.eclipse.draw2d.geometry.Rectangle;
010: import org.eclipse.draw2d.geometry.Transposer;
011:
012: /**
013: * Performs a layout on a container containing {@link AbstractBranch} figures. This layout is
014: * similar to FlowLayout, except that the children are squeezed together to overlap by
015: * comparing their left and right contours.
016: * @author hudsonr
017: * Created on Apr 18, 2003
018: */
019: public class TreeLayout extends AbstractLayout {
020:
021: private int pointOfContact;
022:
023: /**
024: * @see org.eclipse.draw2d.AbstractLayout#calculatePreferredSize(org.eclipse.draw2d.IFigure, int, int)
025: */
026: protected Dimension calculatePreferredSize(IFigure container,
027: int wHint, int hHint) {
028: container.validate();
029: List children = container.getChildren();
030: Rectangle result = new Rectangle().setLocation(container
031: .getClientArea().getLocation());
032: for (int i = 0; i < children.size(); i++)
033: result.union(((IFigure) children.get(i)).getBounds());
034: result.resize(container.getInsets().getWidth(), container
035: .getInsets().getHeight());
036: return result.getSize();
037: }
038:
039: private int[] calculateNewRightContour(int old[], int add[],
040: int shift) {
041: if (old == null)
042: return add;
043: // if (shift < 0)
044: // shift = 0;
045: int result[] = new int[Math.max(old.length, add.length)];
046: System.arraycopy(add, 0, result, 0, add.length);
047: for (int i = add.length; i < result.length; i++)
048: result[i] = old[i] + shift;
049: return result;
050: }
051:
052: private int calculateOverlap(int leftSubtree[], int rightSubtree[]) {
053: pointOfContact = 0;
054: if (leftSubtree == null)
055: return 0;
056: int min = Math.min(leftSubtree.length, rightSubtree.length);
057: int result = Integer.MAX_VALUE;
058: for (int i = 0; i < min; i++) {
059: int current = leftSubtree[i] + rightSubtree[i];
060: if (i > 0)
061: current -= 5;
062: if (current < result) {
063: result = current;
064: pointOfContact = i + 1;
065: }
066: }
067: return result;
068: }
069:
070: /**
071: * @see org.eclipse.draw2d.LayoutManager#layout(org.eclipse.draw2d.IFigure)
072: */
073: public void layout(IFigure container) {
074: // Animation.recordInitialState(container);
075: // if (Animation.playbackState(container))
076: // return;
077: TreeRoot root = ((TreeBranch) container.getParent()).getRoot();
078: Transposer transposer = root.getTransposer();
079: int gap = root.getMinorSpacing();
080: List subtrees = container.getChildren();
081: TreeBranch subtree;
082: int previousSubtreeDepth = 0;
083: int rightContour[] = null;
084: int leftContour[];
085: int contactDepth;
086:
087: Point reference = transposer.t(container.getBounds()
088: .getLocation());
089: Point currentXY = reference.getCopy();
090:
091: for (int i = 0; i < subtrees.size(); i++) {
092: subtree = (TreeBranch) subtrees.get(i);
093:
094: //Give the subtree its preferred size before asking for contours
095: Dimension subtreeSize = subtree.getPreferredSize();
096: subtree.setSize(subtreeSize);
097: subtreeSize = transposer.t(subtreeSize);
098:
099: leftContour = subtree.getContourLeft();
100: int overlap = calculateOverlap(rightContour, leftContour);
101: //if (!subtree.getRoot().isCompressed())
102: overlap = 0;
103: contactDepth = pointOfContact;
104: subtree.setLocation(transposer.t(currentXY.getTranslated(
105: -overlap, 0)));
106:
107: //Setup value for next sibling
108: int advance = gap + subtreeSize.width - overlap;
109: rightContour = calculateNewRightContour(rightContour,
110: subtree.getContourRight(), advance);
111: currentXY.x += advance;
112:
113: /*
114: * In some cases, the current child may extend beyond the left edge of the
115: * container because of the way it overlaps with the previous child. When this
116: * happens, shift all children right.
117: */
118: int shiftRight = reference.x
119: - transposer.t(subtree.getBounds()).x;
120: if (shiftRight > 0) {
121: currentXY.x += shiftRight;
122: Point correction = transposer
123: .t(new Point(shiftRight, 0));
124: for (int j = 0; j <= i; j++)
125: ((IFigure) subtrees.get(j)).translate(correction.x,
126: correction.y);
127: }
128:
129: /*
130: * In some cases, the current child "i" only touches the contour of a distant
131: * sibling "i-n", where n>1. This means that there is extra space that can be
132: * distributed among the intermediate siblings
133: */
134:
135: if (contactDepth > previousSubtreeDepth) {
136: TreeBranch branch = (TreeBranch) subtrees.get(i - 1);
137: int slack = transposer.t(subtree.getBounds()).x
138: - transposer.t(branch.getBounds()).right()
139: - gap
140: + calculateOverlap(branch.getContourRight(),
141: subtree.getContourLeft());
142: int end = i;
143: int begin = end - 1;
144: while (begin > 0
145: && ((TreeBranch) subtrees.get(begin))
146: .getDepth() < contactDepth)
147: begin--;
148:
149: for (int j = begin + 1; j < end; j++) {
150: branch = (TreeBranch) subtrees.get(j);
151: Point shift = transposer.t(new Point(slack
152: * (j - begin) / (end - begin), 0));
153: branch.translate(shift.x, shift.y);
154: }
155: }
156: previousSubtreeDepth = subtree.getDepth();
157: }
158: }
159:
160: }
|