KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > LayoutTreeNode


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * Randy Hudson <hudsonr@us.ibm.com>
11  * - Fix for bug 19524 - Resizing WorkbenchWindow resizes Views
12  * Cagatay Kavukcuoglu <cagatayk@acm.org>
13  * - Fix for bug 10025 - Resizing views should not use height ratios
14  *******************************************************************************/

15 package org.eclipse.ui.internal;
16
17 import java.util.ArrayList JavaDoc;
18
19 import org.eclipse.core.runtime.Assert;
20 import org.eclipse.jface.util.Geometry;
21 import org.eclipse.swt.SWT;
22 import org.eclipse.swt.graphics.Point;
23 import org.eclipse.swt.graphics.Rectangle;
24 import org.eclipse.swt.widgets.Composite;
25 import org.eclipse.swt.widgets.Sash;
26 import org.eclipse.ui.IPageLayout;
27
28 /**
29  * Implementation of a tree node. The node represents a
30  * sash and it allways has two children.
31  */

32 public class LayoutTreeNode extends LayoutTree {
33     
34     static class ChildSizes {
35         int left;
36         int right;
37         boolean resizable = true;
38         
39         public ChildSizes (int l, int r, boolean resize) {
40             left = l;
41             right = r;
42             resizable = resize;
43         }
44     }
45     
46     /* The node children witch may be another node or a leaf */
47     private LayoutTree children[] = new LayoutTree[2];
48
49     /* The sash's width when vertical and hight on horizontal */
50     final static int SASH_WIDTH = 3;
51
52     /**
53      * Initialize this tree with its sash.
54      */

55     public LayoutTreeNode(LayoutPartSash sash) {
56         super(sash);
57     }
58
59     /* (non-Javadoc)
60      * @see org.eclipse.ui.internal.LayoutTree#flushChildren()
61      */

62     public void flushChildren() {
63         super.flushChildren();
64         
65         children[0].flushChildren();
66         children[1].flushChildren();
67     }
68     
69     /**
70      * Traverses the tree to find the part that intersects the given point
71      *
72      * @param toFind
73      * @return the part that intersects the given point
74      */

75     public LayoutPart findPart(Point toFind) {
76         if (!children[0].isVisible()) {
77             if (!children[1].isVisible()) {
78                 return null;
79             }
80
81             return children[1].findPart(toFind);
82         } else {
83             if (!children[1].isVisible()) {
84                 return children[0].findPart(toFind);
85             }
86         }
87
88         LayoutPartSash sash = getSash();
89
90         Rectangle bounds = sash.getBounds();
91
92         if (sash.isVertical()) {
93             if (toFind.x < bounds.x + (bounds.width / 2)) {
94                 return children[0].findPart(toFind);
95             }
96             return children[1].findPart(toFind);
97         } else {
98             if (toFind.y < bounds.y + (bounds.height / 2)) {
99                 return children[0].findPart(toFind);
100             }
101             return children[1].findPart(toFind);
102         }
103     }
104
105     /**
106      * Add the relation ship between the children in the list
107      * and returns the left children.
108      */

109     public LayoutPart computeRelation(ArrayList JavaDoc relations) {
110         PartSashContainer.RelationshipInfo r = new PartSashContainer.RelationshipInfo();
111         r.relative = children[0].computeRelation(relations);
112         r.part = children[1].computeRelation(relations);
113         r.left = getSash().getLeft();
114         r.right = getSash().getRight();
115         r.relationship = getSash().isVertical() ? IPageLayout.RIGHT
116                 : IPageLayout.BOTTOM;
117         relations.add(0, r);
118         return r.relative;
119     }
120
121     /**
122      * Dispose all Sashs in this tree
123      */

124     public void disposeSashes() {
125         children[0].disposeSashes();
126         children[1].disposeSashes();
127         getSash().dispose();
128     }
129
130     /**
131      * Find a LayoutPart in the tree and return its sub-tree. Returns
132      * null if the child is not found.
133      */

134     public LayoutTree find(LayoutPart child) {
135         LayoutTree node = children[0].find(child);
136         if (node != null) {
137             return node;
138         }
139         node = children[1].find(child);
140         return node;
141     }
142
143     /**
144      * Find the part that is in the bottom right position.
145      */

146     public LayoutPart findBottomRight() {
147         if (children[1].isVisible()) {
148             return children[1].findBottomRight();
149         }
150         return children[0].findBottomRight();
151     }
152
153     /**
154      * Go up in the tree finding a parent that is common of both children.
155      * Return the subtree.
156      */

157     public LayoutTreeNode findCommonParent(LayoutPart child1, LayoutPart child2) {
158         return findCommonParent(child1, child2, false, false);
159     }
160
161     /**
162      * Go up in the tree finding a parent that is common of both children.
163      * Return the subtree.
164      */

165     LayoutTreeNode findCommonParent(LayoutPart child1, LayoutPart child2,
166             boolean foundChild1, boolean foundChild2) {
167         if (!foundChild1) {
168             foundChild1 = find(child1) != null;
169         }
170         if (!foundChild2) {
171             foundChild2 = find(child2) != null;
172         }
173         if (foundChild1 && foundChild2) {
174             return this;
175         }
176         if (parent == null) {
177             return null;
178         }
179         return parent
180                 .findCommonParent(child1, child2, foundChild1, foundChild2);
181     }
182
183     /**
184      * Find a sash in the tree and return its sub-tree. Returns
185      * null if the sash is not found.
186      */

187     public LayoutTreeNode findSash(LayoutPartSash sash) {
188         if (this.getSash() == sash) {
189             return this;
190         }
191         LayoutTreeNode node = children[0].findSash(sash);
192         if (node != null) {
193             return node;
194         }
195         node = children[1].findSash(sash);
196         if (node != null) {
197             return node;
198         }
199         return null;
200     }
201
202     /**
203      * Sets the elements in the array of sashes with the
204      * Left,Rigth,Top and Botton sashes. The elements
205      * may be null depending whether there is a shash
206      * beside the <code>part</code>
207      */

208     void findSashes(LayoutTree child, PartPane.Sashes sashes) {
209         Sash sash = (Sash) getSash().getControl();
210         boolean leftOrTop = children[0] == child;
211         if (sash != null) {
212             LayoutPartSash partSash = getSash();
213             //If the child is in the left, the sash
214
//is in the rigth and so on.
215
if (leftOrTop) {
216                 if (partSash.isVertical()) {
217                     if (sashes.right == null) {
218                         sashes.right = sash;
219                     }
220                 } else {
221                     if (sashes.bottom == null) {
222                         sashes.bottom = sash;
223                     }
224                 }
225             } else {
226                 if (partSash.isVertical()) {
227                     if (sashes.left == null) {
228                         sashes.left = sash;
229                     }
230                 } else {
231                     if (sashes.top == null) {
232                         sashes.top = sash;
233                     }
234                 }
235             }
236         }
237         if (getParent() != null) {
238             getParent().findSashes(this, sashes);
239         }
240     }
241
242     /**
243      * Returns the sash of this node.
244      */

245     public LayoutPartSash getSash() {
246         return (LayoutPartSash) part;
247     }
248
249     /**
250      * Returns true if this tree has visible parts otherwise returns false.
251      */

252     public boolean isVisible() {
253         return children[0].isVisible() || children[1].isVisible();
254     }
255
256     /**
257      * Remove the child and this node from the tree
258      */

259     LayoutTree remove(LayoutTree child) {
260         getSash().dispose();
261         if (parent == null) {
262             //This is the root. Return the other child to be the new root.
263
if (children[0] == child) {
264                 children[1].setParent(null);
265                 return children[1];
266             }
267             children[0].setParent(null);
268             return children[0];
269         }
270
271         LayoutTreeNode oldParent = parent;
272         if (children[0] == child) {
273             oldParent.replaceChild(this, children[1]);
274         } else {
275             oldParent.replaceChild(this, children[0]);
276         }
277         return oldParent;
278     }
279
280     /**
281      * Replace a child with a new child and sets the new child's parent.
282      */

283     void replaceChild(LayoutTree oldChild, LayoutTree newChild) {
284         if (children[0] == oldChild) {
285             children[0] = newChild;
286         } else if (children[1] == oldChild) {
287             children[1] = newChild;
288         }
289         newChild.setParent(this);
290         if (!children[0].isVisible() || !children[0].isVisible()) {
291             getSash().dispose();
292         }
293
294         flushCache();
295     }
296
297     /**
298      * Go up from the subtree and return true if all the sash are
299      * in the direction specified by <code>isVertical</code>
300      */

301     public boolean sameDirection(boolean isVertical, LayoutTreeNode subTree) {
302         boolean treeVertical = getSash().isVertical();
303         if (treeVertical != isVertical) {
304             return false;
305         }
306         while (subTree != null) {
307             if (this == subTree) {
308                 return true;
309             }
310             if (subTree.children[0].isVisible()
311                     && subTree.children[1].isVisible()) {
312                 if (subTree.getSash().isVertical() != isVertical) {
313                     return false;
314                 }
315             }
316             subTree = subTree.getParent();
317         }
318         return true;
319     }
320     
321     public int doComputePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredParallel) {
322         assertValidSize(availablePerpendicular);
323         assertValidSize(availableParallel);
324         assertValidSize(preferredParallel);
325         
326         // If one child is invisible, defer to the other child
327
if (!children[0].isVisible()) {
328             return children[1].computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
329         }
330         
331         if (!children[1].isVisible()) {
332             return children[0].computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
333         }
334         
335         if (availableParallel == 0) {
336             return 0;
337         }
338         
339         // If computing the dimension perpendicular to our sash
340
if (width == getSash().isVertical()) {
341             // Compute the child sizes
342
ChildSizes sizes = computeChildSizes(availableParallel, availablePerpendicular,
343                     getSash().getLeft(), getSash().getRight(), preferredParallel);
344             
345             // Return the sum of the child sizes plus the sash size
346
return add(sizes.left, add(sizes.right, SASH_WIDTH));
347         } else {
348             // Computing the dimension parallel to the sash. We will compute and return the preferred size
349
// of whichever child is closest to the ideal size.
350

351             ChildSizes sizes;
352             // First compute the dimension of the child sizes perpendicular to the sash
353
sizes = computeChildSizes(availablePerpendicular, availableParallel,
354                 getSash().getLeft(), getSash().getRight(), availablePerpendicular);
355             
356             // Use this information to compute the dimension of the child sizes parallel to the sash.
357
// Return the preferred size of whichever child is largest
358
int leftSize = children[0].computePreferredSize(width, availableParallel, sizes.left, preferredParallel);
359             
360             // Compute the preferred size of the right child
361
int rightSize = children[1].computePreferredSize(width, availableParallel, sizes.right, preferredParallel);
362             
363             // Return leftSize or rightSize: whichever one is largest
364
int result = rightSize;
365             if (leftSize > rightSize) {
366                 result = leftSize;
367             }
368
369             assertValidSize(result);
370             
371             return result;
372         }
373     }
374     
375     /**
376      * Computes the pixel sizes of this node's children, given the available
377      * space for this node. Note that "width" and "height" actually refer
378      * to the distance perpendicular and parallel to the sash respectively.
379      * That is, their meaning is reversed when computing a horizontal sash.
380      *
381      * @param width the pixel width of a vertical node, or the pixel height
382      * of a horizontal node (INFINITE if unbounded)
383      * @param height the pixel height of a vertical node, or the pixel width
384      * of a horizontal node (INFINITE if unbounded)
385      * @return a struct describing the pixel sizes of the left and right children
386      * (this is a width for horizontal nodes and a height for vertical nodes)
387      */

388     ChildSizes computeChildSizes(int width, int height, int left, int right, int preferredWidth) {
389         Assert.isTrue(children[0].isVisible());
390         Assert.isTrue(children[1].isVisible());
391         assertValidSize(width);
392         assertValidSize(height);
393         assertValidSize(preferredWidth);
394         Assert.isTrue(left >= 0);
395         Assert.isTrue(right >= 0);
396         Assert.isTrue(preferredWidth >= 0);
397         Assert.isTrue(preferredWidth <= width);
398         boolean vertical = getSash().isVertical();
399         
400         if (width <= SASH_WIDTH) {
401             return new ChildSizes(0,0, false);
402         }
403         
404         if (width == INFINITE) {
405             if (preferredWidth == INFINITE) {
406                 return new ChildSizes(children[0].computeMaximumSize(vertical, height),
407                         children[1].computeMaximumSize(vertical, height), false);
408             }
409             
410             if (preferredWidth == 0) {
411                 return new ChildSizes(children[0].computeMinimumSize(vertical, height),
412                         children[1].computeMinimumSize(vertical, height), false);
413             }
414         }
415         
416         int total = left + right;
417
418         // Use all-or-none weighting
419
double wLeft = left, wRight = right;
420         switch (getCompressionBias()) {
421         case -1:
422             wLeft = 0.0;
423             break;
424         case 1:
425             wRight = 0.0;
426             break;
427         default:
428             break;
429         }
430         double wTotal = wLeft + wRight;
431         
432         // Subtract the SASH_WIDTH from preferredWidth and width. From here on, we'll deal with the
433
// width available to the controls and neglect the space used by the sash.
434
preferredWidth = Math.max(0, subtract(preferredWidth, SASH_WIDTH));
435         width = Math.max(0, subtract(width, SASH_WIDTH));
436         
437         int redistribute = subtract(preferredWidth, total);
438         
439         // Compute the minimum and maximum sizes for each child
440
int leftMinimum = children[0].computeMinimumSize(vertical, height);
441         int rightMinimum = children[1].computeMinimumSize(vertical, height);
442         int leftMaximum = children[0].computeMaximumSize(vertical, height);
443         int rightMaximum = children[1].computeMaximumSize(vertical, height);
444         
445         // Keep track of the available space for each child, given the minimum size of the other child
446
int leftAvailable = Math.min(leftMaximum, Math.max(0, subtract(width, rightMinimum)));
447         int rightAvailable = Math.min(rightMaximum, Math.max(0, subtract(width, leftMinimum)));
448         
449         // Figure out the ideal size of the left child
450
int idealLeft = Math.max(leftMinimum, Math.min(preferredWidth,
451                 left + (int) Math.round(redistribute * wLeft / wTotal)));
452         
453         // If the right child can't use all its available space, let the left child fill it in
454
idealLeft = Math.max(idealLeft, preferredWidth - rightAvailable);
455         // Ensure the left child doesn't get larger than its available space
456
idealLeft = Math.min(idealLeft, leftAvailable);
457         
458         // Check if the left child would prefer to be a different size
459
idealLeft = children[0].computePreferredSize(vertical, leftAvailable, height, idealLeft);
460         
461         // Ensure that the left child is larger than its minimum size
462
idealLeft = Math.max(idealLeft, leftMinimum);
463         idealLeft = Math.min(idealLeft, leftAvailable);
464         
465         // Compute the right child width
466
int idealRight = Math.max(rightMinimum, preferredWidth - idealLeft);
467         
468         rightAvailable = Math.max(0, Math.min(rightAvailable, subtract(width, idealLeft)));
469         idealRight = Math.min(idealRight, rightAvailable);
470         idealRight = children[1].computePreferredSize(vertical, rightAvailable, height, idealRight);
471         idealRight = Math.max(idealRight, rightMinimum);
472         
473         return new ChildSizes(idealLeft, idealRight, leftMaximum > leftMinimum
474                 && rightMaximum > rightMinimum
475                 && leftMinimum + rightMinimum < width);
476     }
477     
478     protected int doGetSizeFlags(boolean width) {
479         if (!children[0].isVisible()) {
480             return children[1].getSizeFlags(width);
481         }
482         
483         if (!children[1].isVisible()) {
484             return children[0].getSizeFlags(width);
485         }
486         
487         int leftFlags = children[0].getSizeFlags(width);
488         int rightFlags = children[1].getSizeFlags(width);
489         
490         return ((leftFlags | rightFlags) & ~SWT.MAX) | (leftFlags & rightFlags & SWT.MAX);
491     }
492     
493     /**
494      * Resize the parts on this tree to fit in <code>bounds</code>.
495      */

496     public void doSetBounds(Rectangle bounds) {
497         if (!children[0].isVisible()) {
498             children[1].setBounds(bounds);
499             getSash().setVisible(false);
500             return;
501         }
502         if (!children[1].isVisible()) {
503             children[0].setBounds(bounds);
504             getSash().setVisible(false);
505             return;
506         }
507         
508         bounds = Geometry.copy(bounds);
509         
510         boolean vertical = getSash().isVertical();
511
512         // If this is a horizontal sash, flip coordinate systems so
513
// that we can eliminate special cases
514
if (!vertical) {
515             Geometry.flipXY(bounds);
516         }
517
518         ChildSizes childSizes = computeChildSizes(bounds.width, bounds.height, getSash().getLeft(), getSash().getRight(), bounds.width);
519         
520         getSash().setVisible(true);
521         getSash().setEnabled(childSizes.resizable);
522         
523         Rectangle leftBounds = new Rectangle(bounds.x, bounds.y, childSizes.left, bounds.height);
524         Rectangle sashBounds = new Rectangle(leftBounds.x + leftBounds.width, bounds.y, SASH_WIDTH, bounds.height);
525         Rectangle rightBounds = new Rectangle(sashBounds.x + sashBounds.width, bounds.y, childSizes.right, bounds.height);
526         
527         if (!vertical) {
528             Geometry.flipXY(leftBounds);
529             Geometry.flipXY(sashBounds);
530             Geometry.flipXY(rightBounds);
531         }
532         
533         getSash().setBounds(sashBounds);
534         children[0].setBounds(leftBounds);
535         children[1].setBounds(rightBounds);
536     }
537
538     /* (non-Javadoc)
539      * @see org.eclipse.ui.internal.LayoutTree#createControl(org.eclipse.swt.widgets.Composite)
540      */

541     public void createControl(Composite parent) {
542         children[0].createControl(parent);
543         children[1].createControl(parent);
544         getSash().createControl(parent);
545         
546         super.createControl(parent);
547     }
548     
549     //Added by hudsonr@us.ibm.com - bug 19524
550

551     public boolean isCompressible() {
552         return children[0].isCompressible() || children[1].isCompressible();
553     }
554
555     /**
556      * Returns 0 if there is no bias. Returns -1 if the first child should be of
557      * fixed size, and the second child should be compressed. Returns 1 if the
558      * second child should be of fixed size.
559      * @return the bias
560      */

561     public int getCompressionBias() {
562         boolean left = children[0].isCompressible();
563         boolean right = children[1].isCompressible();
564         if (left == right) {
565             return 0;
566         }
567         if (right) {
568             return -1;
569         }
570         return 1;
571     }
572     
573     boolean isLeftChild(LayoutTree toTest) {
574         return children[0] == toTest;
575     }
576
577     LayoutTree getChild(boolean left) {
578         int index = left ? 0 : 1;
579         return (children[index]);
580     }
581
582     /**
583      * Sets a child in this node
584      */

585     void setChild(boolean left, LayoutPart part) {
586         LayoutTree child = new LayoutTree(part);
587         setChild(left, child);
588         flushCache();
589     }
590
591     /**
592      * Sets a child in this node
593      */

594     void setChild(boolean left, LayoutTree child) {
595         int index = left ? 0 : 1;
596         children[index] = child;
597         child.setParent(this);
598         flushCache();
599     }
600
601     /**
602      * Returns a string representation of this object.
603      */

604     public String JavaDoc toString() {
605         String JavaDoc s = "<null>\n";//$NON-NLS-1$
606
if (part.getControl() != null) {
607             s = "<@" + part.getControl().hashCode() + ">\n";//$NON-NLS-2$//$NON-NLS-1$
608
}
609         String JavaDoc result = "["; //$NON-NLS-1$
610
if (children[0].getParent() != this) {
611             result = result + "{" + children[0] + "}" + s;//$NON-NLS-2$//$NON-NLS-1$
612
} else {
613             result = result + children[0] + s;
614         }
615
616         if (children[1].getParent() != this) {
617             result = result + "{" + children[1] + "}]";//$NON-NLS-2$//$NON-NLS-1$
618
} else {
619             result = result + children[1] + "]";//$NON-NLS-1$
620
}
621         return result;
622     }
623     
624     /**
625      * Create the sashes if the children are visible
626      * and dispose it if they are not.
627      */

628 // public void updateSashes(Composite parent) {
629
// if (parent == null)
630
// return;
631
// children[0].updateSashes(parent);
632
// children[1].updateSashes(parent);
633
// if (children[0].isVisible() && children[1].isVisible())
634
// getSash().createControl(parent);
635
// else
636
// getSash().dispose();
637
// }
638

639     /**
640      * Writes a description of the layout to the given string buffer.
641      * This is used for drag-drop test suites to determine if two layouts are the
642      * same. Like a hash code, the description should compare as equal iff the
643      * layouts are the same. However, it should be user-readable in order to
644      * help debug failed tests. Although these are english readable strings,
645      * they should not be translated or equality tests will fail.
646      *
647      * @param buf
648      */

649     public void describeLayout(StringBuffer JavaDoc buf) {
650         if (!(children[0].isVisible())) {
651             if (!children[1].isVisible()) {
652                 return;
653             }
654
655             children[1].describeLayout(buf);
656             return;
657         }
658
659         if (!children[1].isVisible()) {
660             children[0].describeLayout(buf);
661             return;
662         }
663
664         buf.append("("); //$NON-NLS-1$
665
children[0].describeLayout(buf);
666
667         buf.append(getSash().isVertical() ? "|" : "-"); //$NON-NLS-1$ //$NON-NLS-2$
668

669         children[1].describeLayout(buf);
670         buf.append(")"); //$NON-NLS-1$
671
}
672
673 }
674
Popular Tags