KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  * Cagatay Kavukcuoglu <cagatayk@acm.org>
11  * - Fix for bug 10025 - Resizing views should not use height ratios
12  * Chris Gross chris.gross@us.ibm.com Bug 107443
13  *******************************************************************************/

14 package org.eclipse.ui.internal;
15
16 import java.util.ArrayList JavaDoc;
17
18 import org.eclipse.core.runtime.Assert;
19 import org.eclipse.jface.util.Geometry;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.ControlAdapter;
22 import org.eclipse.swt.events.ControlEvent;
23 import org.eclipse.swt.events.ControlListener;
24 import org.eclipse.swt.graphics.Cursor;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.graphics.Rectangle;
27 import org.eclipse.swt.widgets.Composite;
28 import org.eclipse.swt.widgets.Control;
29 import org.eclipse.ui.IPageLayout;
30 import org.eclipse.ui.IViewReference;
31 import org.eclipse.ui.internal.dnd.AbstractDropTarget;
32 import org.eclipse.ui.internal.dnd.DragUtil;
33 import org.eclipse.ui.internal.dnd.IDragOverListener;
34 import org.eclipse.ui.internal.dnd.IDropTarget;
35 import org.eclipse.ui.internal.dnd.SwtUtil;
36
37 /**
38  * Abstract container that groups various layout
39  * parts (possibly other containers) together as
40  * a unit. Manages the placement and size of these
41  * layout part based on the location of sashes within
42  * the container.
43  */

44 public abstract class PartSashContainer extends LayoutPart implements
45         ILayoutContainer, IDragOverListener {
46
47     protected Composite parent;
48
49     protected ControlListener resizeListener;
50
51     protected LayoutTree root;
52     
53     private Composite parentWidget;
54
55     private LayoutPart zoomedPart;
56
57     protected WorkbenchPage page;
58
59     boolean active = false;
60     boolean layoutDirty = false;
61
62     /* Array of LayoutPart */
63     protected ArrayList JavaDoc children = new ArrayList JavaDoc();
64     
65     private SashContainerDropTarget dropTarget;
66
67     protected static class RelationshipInfo {
68         protected LayoutPart part;
69
70         protected LayoutPart relative;
71
72         protected int relationship;
73
74         /**
75          * Preferred size for the left child (this would be the size, in pixels of the child
76          * at the time the sash was last moved)
77          */

78         protected int left;
79
80         /**
81          * Preferred size for the right child (this would be the size, in pixels of the child
82          * at the time the sash was last moved)
83          */

84         protected int right;
85
86         /**
87          * Computes the "ratio" for this container. That is, the ratio of the left side over
88          * the sum of left + right. This is only used for serializing PartSashContainers in
89          * a form that can be read by old versions of Eclipse. This can be removed if this
90          * is no longer required.
91          *
92          * @return the pre-Eclipse 3.0 sash ratio
93          */

94         public float getRatio() {
95             int total = left + right;
96             if (total > 0) {
97                 return (float) left / (float) total;
98             }
99             
100             return 0.5f;
101         }
102     }
103
104     private class SashContainerDropTarget extends AbstractDropTarget {
105         private int side;
106
107         private int cursor;
108
109         private LayoutPart targetPart;
110
111         private LayoutPart sourcePart;
112
113         public SashContainerDropTarget(LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
114             this.setTarget(sourcePart, side, cursor, targetPart);
115         }
116         
117         public void setTarget(LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
118             this.side = side;
119             this.targetPart = targetPart;
120             this.sourcePart = sourcePart;
121             this.cursor = cursor;
122         }
123
124         public void drop() {
125             if (side != SWT.NONE) {
126                 LayoutPart visiblePart = sourcePart;
127
128                 if (sourcePart instanceof PartStack) {
129                     visiblePart = getVisiblePart((PartStack) sourcePart);
130                 }
131
132                 dropObject(getVisibleParts(sourcePart), visiblePart,
133                         targetPart, side);
134             }
135         }
136
137         public Cursor getCursor() {
138             return DragCursors.getCursor(DragCursors
139                     .positionToDragCursor(cursor));
140         }
141
142         public Rectangle getSnapRectangle() {
143             Rectangle targetBounds;
144
145             if (targetPart != null) {
146                 targetBounds = DragUtil.getDisplayBounds(targetPart
147                         .getControl());
148             } else {
149                 targetBounds = DragUtil.getDisplayBounds(getParent());
150             }
151
152             if (side == SWT.CENTER || side == SWT.NONE) {
153                 return targetBounds;
154             }
155
156             int distance = Geometry.getDimension(targetBounds, !Geometry
157                     .isHorizontal(side));
158
159             return Geometry.getExtrudedEdge(targetBounds,
160                     (int) (distance * getDockingRatio(sourcePart, targetPart)),
161                     side);
162         }
163     }
164
165     public PartSashContainer(String JavaDoc id, final WorkbenchPage page, Composite parentWidget) {
166         super(id);
167         this.page = page;
168         this.parentWidget = parentWidget;
169         resizeListener = new ControlAdapter() {
170             public void controlResized(ControlEvent e) {
171                 resizeSashes();
172             }
173         };
174     }
175
176     /* (non-Javadoc)
177      * @see org.eclipse.ui.internal.ILayoutContainer#obscuredByZoom(org.eclipse.ui.internal.LayoutPart)
178      */

179     public boolean childObscuredByZoom(LayoutPart toTest) {
180         LayoutPart zoomPart = getZoomedPart();
181         
182         if (zoomPart != null && toTest != zoomPart) {
183             return true;
184         }
185         return isObscuredByZoom();
186     }
187     
188     /**
189      * Given an object associated with a drag (a PartPane or PartStack), this returns
190      * the actual PartPanes being dragged.
191      *
192      * @param pane
193      * @return
194      */

195     private PartPane[] getVisibleParts(LayoutPart pane) {
196         if (pane instanceof PartPane) {
197             return new PartPane[] { (PartPane) pane };
198         } else if (pane instanceof PartStack) {
199             PartStack stack = (PartStack) pane;
200
201             LayoutPart[] children = stack.getChildren();
202             ArrayList JavaDoc result = new ArrayList JavaDoc(children.length);
203             for (int idx = 0; idx < children.length; idx++) {
204                 LayoutPart next = children[idx];
205                 if (next instanceof PartPane) {
206                     result.add(next);
207                 }
208             }
209
210             return (PartPane[]) result.toArray(new PartPane[result.size()]);
211         }
212
213         return new PartPane[0];
214     }
215
216     /**
217      * Find the sashs around the specified part.
218      */

219     public void findSashes(LayoutPart pane, PartPane.Sashes sashes) {
220         if (root == null) {
221             return;
222         }
223         LayoutTree part = root.find(pane);
224         if (part == null) {
225             return;
226         }
227         part.findSashes(sashes);
228     }
229
230     /**
231      * Add a part.
232      */

233     public void add(LayoutPart child) {
234         if (child == null) {
235             return;
236         }
237
238         addEnhanced(child, SWT.RIGHT, 0.5f, findBottomRight());
239     }
240
241     /**
242      * Add a new part relative to another. This should be used in place of <code>add</code>.
243      * It differs as follows:
244      * <ul>
245      * <li>relationships are specified using SWT direction constants</li>
246      * <li>the ratio applies to the newly added child -- not the upper-left child</li>
247      * </ul>
248      *
249      * @param child new part to add to the layout
250      * @param swtDirectionConstant one of SWT.TOP, SWT.BOTTOM, SWT.LEFT, or SWT.RIGHT
251      * @param ratioForNewPart a value between 0.0 and 1.0 specifying how much space will be allocated for the newly added part
252      * @param relative existing part indicating where the new child should be attached
253      * @since 3.0
254      */

255     void addEnhanced(LayoutPart child, int swtDirectionConstant,
256             float ratioForNewPart, LayoutPart relative) {
257         int relativePosition = PageLayout
258                 .swtConstantToLayoutPosition(swtDirectionConstant);
259
260         float ratioForUpperLeftPart;
261
262         if (relativePosition == IPageLayout.RIGHT
263                 || relativePosition == IPageLayout.BOTTOM) {
264             ratioForUpperLeftPart = 1.0f - ratioForNewPart;
265         } else {
266             ratioForUpperLeftPart = ratioForNewPart;
267         }
268
269         add(child, relativePosition, ratioForUpperLeftPart, relative);
270     }
271
272     /**
273      * Add a part relative to another. For compatibility only. New code should use
274      * addEnhanced, above.
275      *
276      * @param child the new part to add
277      * @param relationship one of PageLayout.TOP, PageLayout.BOTTOM, PageLayout.LEFT, or PageLayout.RIGHT
278      * @param ratio a value between 0.0 and 1.0, indicating how much space will be allocated to the UPPER-LEFT pane
279      * @param relative part where the new part will be attached
280      */

281     public void add(LayoutPart child, int relationship, float ratio,
282             LayoutPart relative) {
283         boolean isHorizontal = (relationship == IPageLayout.LEFT || relationship == IPageLayout.RIGHT);
284
285         LayoutTree node = null;
286         if (root != null && relative != null) {
287             node = root.find(relative);
288         }
289
290         Rectangle bounds;
291         if (getParent() == null) {
292             Control control = getPage().getClientComposite();
293             if (control != null && !control.isDisposed()) {
294                 bounds = control.getBounds();
295             } else {
296                 bounds = new Rectangle(0, 0, 800, 600);
297             }
298             bounds.x = 0;
299             bounds.y = 0;
300         } else {
301             bounds = getBounds();
302         }
303
304         int totalSize = measureTree(bounds, node, isHorizontal);
305
306         int left = (int) (totalSize * ratio);
307         int right = totalSize - left;
308
309         add(child, relationship, left, right, relative);
310     }
311
312     static int measureTree(Rectangle outerBounds, LayoutTree toMeasure,
313             boolean horizontal) {
314         if (toMeasure == null) {
315             return Geometry.getDimension(outerBounds, horizontal);
316         }
317
318         LayoutTreeNode parent = toMeasure.getParent();
319         if (parent == null) {
320             return Geometry.getDimension(outerBounds, horizontal);
321         }
322
323         if (parent.getSash().isHorizontal() == horizontal) {
324             return measureTree(outerBounds, parent, horizontal);
325         }
326
327         boolean isLeft = parent.isLeftChild(toMeasure);
328
329         LayoutTree otherChild = parent.getChild(!isLeft);
330         if (otherChild.isVisible()) {
331             int left = parent.getSash().getLeft();
332             int right = parent.getSash().getRight();
333             int childSize = isLeft ? left : right;
334
335             int bias = parent.getCompressionBias();
336
337             // Normalize bias: 1 = we're fixed, -1 = other child is fixed
338
if (isLeft) {
339                 bias = -bias;
340             }
341
342             if (bias == 1) {
343                 // If we're fixed, return the fixed size
344
return childSize;
345             } else if (bias == -1) {
346
347                 // If the other child is fixed, return the size of the parent minus the fixed size of the
348
// other child
349
return measureTree(outerBounds, parent, horizontal)
350                         - (left + right - childSize);
351             }
352
353             // Else return the size of the parent, scaled appropriately
354
return measureTree(outerBounds, parent, horizontal) * childSize
355                     / (left + right);
356         }
357
358         return measureTree(outerBounds, parent, horizontal);
359     }
360
361     protected void addChild(RelationshipInfo info) {
362         LayoutPart child = info.part;
363
364         children.add(child);
365
366         if (root == null) {
367             root = new LayoutTree(child);
368         } else {
369             //Add the part to the tree.
370
int vertical = (info.relationship == IPageLayout.LEFT || info.relationship == IPageLayout.RIGHT) ? SWT.VERTICAL
371                     : SWT.HORIZONTAL;
372             boolean left = info.relationship == IPageLayout.LEFT
373                     || info.relationship == IPageLayout.TOP;
374             LayoutPartSash sash = new LayoutPartSash(this, vertical);
375             sash.setSizes(info.left, info.right);
376             if ((parent != null) && !(child instanceof PartPlaceholder)) {
377                 sash.createControl(parent);
378             }
379             root = root.insert(child, left, sash, info.relative);
380         }
381
382         childAdded(child);
383
384         if (active) {
385             child.createControl(parent);
386             child.setVisible(true);
387             child.setContainer(this);
388             resizeChild(child);
389         }
390
391     }
392
393     /**
394      * Adds the child using ratio and position attributes
395      * from the specified placeholder without replacing
396      * the placeholder
397      *
398      * FIXME: I believe there is a bug in computeRelation()
399      * when a part is positioned relative to the editorarea.
400      * We end up with a null relative and 0.0 for a ratio.
401      */

402     void addChildForPlaceholder(LayoutPart child, LayoutPart placeholder) {
403         RelationshipInfo newRelationshipInfo = new RelationshipInfo();
404         newRelationshipInfo.part = child;
405         if (root != null) {
406             newRelationshipInfo.relationship = IPageLayout.RIGHT;
407             newRelationshipInfo.relative = root.findBottomRight();
408             newRelationshipInfo.left = 200;
409             newRelationshipInfo.right = 200;
410         }
411
412         // find the relationship info for the placeholder
413
RelationshipInfo[] relationships = computeRelation();
414         for (int i = 0; i < relationships.length; i++) {
415             RelationshipInfo info = relationships[i];
416             if (info.part == placeholder) {
417                 newRelationshipInfo.left = info.left;
418                 newRelationshipInfo.right = info.right;
419                 newRelationshipInfo.relationship = info.relationship;
420                 newRelationshipInfo.relative = info.relative;
421             }
422         }
423
424         addChild(newRelationshipInfo);
425         flushLayout();
426     }
427
428     /**
429      * See ILayoutContainer#allowBorder
430      */

431     public boolean allowsBorder() {
432         return true;
433     }
434
435     /**
436      * Notification that a child layout part has been
437      * added to the container. Subclasses may override
438      * this method to perform any container specific
439      * work.
440      */

441     protected void childAdded(LayoutPart child) {
442         if (isDeferred()) {
443             child.deferUpdates(true);
444         }
445     }
446
447     /**
448      * Notification that a child layout part has been
449      * removed from the container. Subclasses may override
450      * this method to perform any container specific
451      * work.
452      */

453     protected void childRemoved(LayoutPart child) {
454         if (isDeferred()) {
455             child.deferUpdates(false);
456         }
457     }
458
459     /**
460      * Returns an array with all the relation ship between the
461      * parts.
462      */

463     public RelationshipInfo[] computeRelation() {
464         LayoutTree treeRoot = root;
465         ArrayList JavaDoc list = new ArrayList JavaDoc();
466         if (treeRoot == null) {
467             return new RelationshipInfo[0];
468         }
469         RelationshipInfo r = new RelationshipInfo();
470         r.part = treeRoot.computeRelation(list);
471         list.add(0, r);
472         RelationshipInfo[] result = new RelationshipInfo[list.size()];
473         list.toArray(result);
474         return result;
475     }
476
477     public void setActive(boolean isActive) {
478         if (isActive == active) {
479             return;
480         }
481         
482         active = isActive;
483         
484         ArrayList JavaDoc children = (ArrayList JavaDoc) this.children.clone();
485         for (int i = 0, length = children.size(); i < length; i++) {
486             LayoutPart child = (LayoutPart) children.get(i);
487             
488             if (child instanceof PartStack) {
489                 PartStack stack = (PartStack) child;
490                 stack.setActive(isActive);
491             }
492         }
493         
494         if (isActive) {
495             
496             createControl(parentWidget);
497             
498             parent.addControlListener(resizeListener);
499
500             DragUtil.addDragTarget(parent, this);
501             DragUtil.addDragTarget(parent.getShell(), this);
502             
503             //ArrayList children = (ArrayList) this.children.clone();
504
for (int i = 0, length = children.size(); i < length; i++) {
505                 LayoutPart child = (LayoutPart) children.get(i);
506                 child.setContainer(this);
507                 child.setVisible(zoomedPart == null || child == zoomedPart);
508                 if (!(child instanceof PartStack)) {
509                     if (root != null) {
510                         LayoutTree node = root.find(child);
511                         if (node != null) {
512                             node.flushCache();
513                         }
514                     }
515                 }
516             }
517             
518             if (root != null) {
519                 //root.flushChildren();
520
if (!isZoomed()) {
521                     root.createControl(parent);
522                 }
523             }
524             
525             resizeSashes();
526         } else {
527             DragUtil.removeDragTarget(parent, this);
528             DragUtil.removeDragTarget(parent.getShell(), this);
529
530             // remove all Listeners
531
if (resizeListener != null && parent != null) {
532                 parent.removeControlListener(resizeListener);
533             }
534
535             if (children != null) {
536                 for (int i = 0, length = children.size(); i < length; i++) {
537                     LayoutPart child = (LayoutPart) children.get(i);
538                     child.setContainer(null);
539                     if (child instanceof PartStack) {
540                         child.setVisible(false);
541                     }
542                 }
543             }
544             
545             disposeSashes();
546             
547             //dispose();
548
}
549     }
550     
551     /**
552      * @see LayoutPart#getControl
553      */

554     public void createControl(Composite parentWidget) {
555         if (this.parent != null) {
556             return;
557         }
558
559         parent = createParent(parentWidget);
560
561         ArrayList JavaDoc children = (ArrayList JavaDoc) this.children.clone();
562         for (int i = 0, length = children.size(); i < length; i++) {
563             LayoutPart child = (LayoutPart) children.get(i);
564             child.createControl(parent);
565         }
566
567     }
568
569     /**
570      * Subclasses override this method to specify
571      * the composite to use to parent all children
572      * layout parts it contains.
573      */

574     protected abstract Composite createParent(Composite parentWidget);
575
576     /**
577      * @see LayoutPart#dispose
578      */

579     public void dispose() {
580         if (parent == null) {
581             return;
582         }
583
584         if (children != null) {
585             for (int i = 0, length = children.size(); i < length; i++) {
586                 LayoutPart child = (LayoutPart) children.get(i);
587
588                 // In PartSashContainer dispose really means deactivate, so we
589
// only dispose PartTabFolders.
590
if (child instanceof PartStack) {
591                     child.dispose();
592                 }
593             }
594         }
595         disposeParent();
596         this.parent = null;
597     }
598
599     /**
600      * Subclasses override this method to dispose
601      * of any swt resources created during createParent.
602      */

603     protected abstract void disposeParent();
604
605     /**
606      * Dispose all sashs used in this perspective.
607      */

608     public void disposeSashes() {
609         if (root != null) {
610             root.disposeSashes();
611         }
612     }
613
614     /* (non-Javadoc)
615      * @see org.eclipse.ui.internal.LayoutPart#setVisible(boolean)
616      */

617     public void setVisible(boolean makeVisible) {
618         
619         if (makeVisible == getVisible()) {
620             return;
621         }
622         
623         if (!SwtUtil.isDisposed(this.parent)) {
624             this.parent.setEnabled(makeVisible);
625         }
626         super.setVisible(makeVisible);
627         
628         ArrayList JavaDoc children = (ArrayList JavaDoc) this.children.clone();
629         for (int i = 0, length = children.size(); i < length; i++) {
630             LayoutPart child = (LayoutPart) children.get(i);
631             child.setVisible(makeVisible && (zoomedPart == null || child == zoomedPart));
632         }
633     }
634     
635     /**
636      * Return the most bottom right part or null if none.
637      */

638     public LayoutPart findBottomRight() {
639         if (root == null) {
640             return null;
641         }
642         return root.findBottomRight();
643     }
644
645     /**
646      * @see LayoutPart#getBounds
647      */

648     public Rectangle getBounds() {
649         return this.parent.getBounds();
650     }
651
652     /**
653      * @see ILayoutContainer#getChildren
654      */

655     public LayoutPart[] getChildren() {
656         LayoutPart[] result = new LayoutPart[children.size()];
657         children.toArray(result);
658         return result;
659     }
660
661     /**
662      * @see LayoutPart#getControl
663      */

664     public Control getControl() {
665         return this.parent;
666     }
667
668     public LayoutTree getLayoutTree() {
669         return root;
670     }
671
672     /**
673      * For themes.
674      *
675      * @return the current WorkbenchPage.
676      */

677     public WorkbenchPage getPage() {
678         return page;
679     }
680
681     /**
682      * Returns the composite used to parent all the
683      * layout parts contained within.
684      */

685     public Composite getParent() {
686         return parent;
687     }
688
689     protected boolean isChild(LayoutPart part) {
690         return children.indexOf(part) >= 0;
691     }
692
693     /**
694      * Returns whether this container is zoomed.
695      */

696     public boolean isZoomed() {
697         return (zoomedPart != null);
698     }
699
700     /* (non-Javadoc)
701      * @see org.eclipse.ui.internal.LayoutPart#forceLayout(org.eclipse.ui.internal.LayoutPart)
702      */

703     public void resizeChild(LayoutPart childThatChanged) {
704         if (root != null) {
705             LayoutTree tree = root.find(childThatChanged);
706             
707             if (tree != null) {
708                 tree.flushCache();
709             }
710         }
711         
712         flushLayout();
713
714     }
715
716     /**
717      * Remove a part.
718      */

719     public void remove(LayoutPart child) {
720         if (child == getZoomedPart()) {
721             childRequestZoomOut();
722         }
723
724         if (!isChild(child)) {
725             return;
726         }
727
728         children.remove(child);
729         if (root != null) {
730             root = root.remove(child);
731         }
732         childRemoved(child);
733
734         if (active) {
735             child.setVisible(false);
736             child.setContainer(null);
737             flushLayout();
738         }
739     }
740
741     /* (non-Javadoc)
742      * @see org.eclipse.ui.internal.LayoutPart#forceLayout()
743      */

744     public void flushLayout() {
745         layoutDirty = true;
746         super.flushLayout();
747         
748         if (layoutDirty) {
749             resizeSashes();
750         }
751     }
752     
753     /**
754      * Replace one part with another.
755      */

756     public void replace(LayoutPart oldChild, LayoutPart newChild) {
757
758         if (!isChild(oldChild)) {
759             return;
760         }
761         
762         if (oldChild == getZoomedPart()) {
763             if (newChild instanceof PartPlaceholder) {
764                 childRequestZoomOut();
765             } else {
766                 zoomedPart.setZoomed(false);
767                 zoomedPart = newChild;
768                 zoomedPart.setZoomed(true);
769             }
770         }
771
772         children.remove(oldChild);
773         children.add(newChild);
774
775         childAdded(newChild);
776
777         if (root != null) {
778             LayoutTree leaf = null;
779
780             leaf = root.find(oldChild);
781             if (leaf != null) {
782                 leaf.setPart(newChild);
783             }
784         }
785
786         childRemoved(oldChild);
787         if (active) {
788             oldChild.setVisible(false);
789             oldChild.setContainer(null);
790             newChild.createControl(parent);
791             newChild.setContainer(this);
792             newChild.setVisible(zoomedPart == null || zoomedPart == newChild);
793             resizeChild(newChild);
794         }
795     }
796
797     private void resizeSashes() {
798         layoutDirty = false;
799         if (!active) {
800             return;
801         }
802         
803         if (isZoomed()) {
804             getZoomedPart().setBounds(parent.getClientArea());
805         } else {
806             if (root != null) {
807                 root.setBounds(parent.getClientArea());
808             }
809         }
810     }
811
812     /**
813      * Returns the maximum size that can be utilized by this part if the given width and
814      * height are available. Parts can overload this if they have a quantized set of preferred
815      * sizes.
816      *
817      * @param width available horizontal space (pixels)
818      * @return returns a new point where point.x is <= availableWidth and point.y is <= availableHeight
819      */

820     public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredParallel) {
821         if (isZoomed()) {
822             return getZoomedPart().computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
823         }
824         
825         if (root != null) {
826             return root.computePreferredSize(width, availableParallel, availablePerpendicular, preferredParallel);
827         }
828                 
829         return preferredParallel;
830     }
831     
832     public int getSizeFlags(boolean width) {
833         if (isZoomed()) {
834             return getZoomedPart().getSizeFlags(width);
835         }
836         
837         if (root != null) {
838             return root.getSizeFlags(width);
839         }
840         
841         return 0;
842     }
843     
844     /**
845      * @see LayoutPart#setBounds
846      */

847     public void setBounds(Rectangle r) {
848         this.parent.setBounds(r);
849     }
850     
851     /**
852      * Zoom in on a particular layout part.
853      *
854      * The implementation of zoom is quite simple. When zoom occurs we create
855      * a zoom root which only contains the zoom part. We store the old
856      * root in unzoomRoot and then active the zoom root. When unzoom occurs
857      * we restore the unzoomRoot and dispose the zoom root.
858      *
859      * Note: Method assumes we are active.
860      */

861     private void zoomIn(LayoutPart part) {
862         // Sanity check.
863
if (isZoomed()) {
864             return;
865         }
866
867         // Hide the sashes
868
root.disposeSashes();
869         
870         // Make all parts invisible except for the zoomed part
871
LayoutPart[] children = getChildren();
872         for (int i = 0; i < children.length; i++) {
873             LayoutPart child = children[i];
874             child.setVisible(child == part);
875         }
876         
877         zoomedPart = part;
878                 
879         // Notify the part that it has been zoomed
880
part.setZoomed(true);
881         
882         // Remember that we need to trigger a layout
883
layoutDirty = true;
884     }
885
886     /**
887      * Returns the currently zoomed part or null if none
888      *
889      * @return the currently zoomed part or null if none
890      * @since 3.1
891      */

892     public LayoutPart getZoomedPart() {
893         return zoomedPart;
894     }
895     
896     public void childRequestZoomIn(LayoutPart toZoom) {
897         if (!SwtUtil.isDisposed(this.parent)) {
898             this.parent.setRedraw(false);
899         }
900         try {
901             zoomIn(toZoom);
902             
903             requestZoomIn();
904             
905             if (layoutDirty) {
906                 resizeSashes();
907             }
908         } finally {
909             if (!SwtUtil.isDisposed(this.parent)) {
910                 this.parent.setRedraw(true);
911             }
912         }
913     }
914     
915     public void childRequestZoomOut() {
916         if (!SwtUtil.isDisposed(this.parent)) {
917             this.parent.setRedraw(false);
918         }
919         try {
920             zoomOut();
921             
922             requestZoomOut();
923             
924             if (layoutDirty) {
925                 resizeSashes();
926             }
927         } finally {
928             if (!SwtUtil.isDisposed(this.parent)) {
929                 this.parent.setRedraw(true);
930             }
931         }
932     }
933     
934     /* (non-Javadoc)
935      * @see org.eclipse.ui.internal.LayoutPart#setZoomed(boolean)
936      */

937     public void setZoomed(boolean isZoomed) {
938         if (!isZoomed) {
939             zoomOut();
940         } else {
941             if (!isZoomed()) {
942                 LayoutPart toZoom = pickPartToZoom();
943                 
944                 if (toZoom != null) {
945                     zoomIn(toZoom);
946                 }
947             }
948         }
949         super.setZoomed(isZoomed);
950     }
951     
952     public LayoutPart pickPartToZoom() {
953         return findBottomRight();
954     }
955     
956     /**
957      * Zoom out.
958      *
959      * See zoomIn for implementation details.
960      *
961      * Note: Method assumes we are active.
962      */

963     private void zoomOut() {
964         // Sanity check.
965
if (!isZoomed()) {
966             return;
967         }
968                
969         LayoutPart zoomedPart = this.zoomedPart;
970         this.zoomedPart = null;
971         // Inform the part that it is no longer zoomed
972
zoomedPart.setZoomed(false);
973         
974         // Make all children visible
975
LayoutPart[] children = getChildren();
976         for (int i = 0; i < children.length; i++) {
977             LayoutPart child = children[i];
978             
979             child.setVisible(true);
980         }
981         
982         // Recreate the sashes
983
root.createControl(getParent());
984         
985         // Ensure that the part being un-zoomed will have its size refreshed.
986
LayoutTree node = root.find(zoomedPart);
987         node.flushCache();
988
989         layoutDirty = true;
990     }
991
992     /* (non-Javadoc)
993      * @see org.eclipse.ui.internal.dnd.IDragOverListener#drag(org.eclipse.swt.widgets.Control, java.lang.Object, org.eclipse.swt.graphics.Point, org.eclipse.swt.graphics.Rectangle)
994      */

995     public IDropTarget drag(Control currentControl, Object JavaDoc draggedObject,
996             Point position, Rectangle dragRectangle) {
997         if (!(draggedObject instanceof LayoutPart)) {
998             return null;
999         }
1000
1001        final LayoutPart sourcePart = (LayoutPart) draggedObject;
1002
1003        if (!isStackType(sourcePart) && !isPaneType(sourcePart)) {
1004            return null;
1005        }
1006
1007        boolean differentWindows = sourcePart.getWorkbenchWindow() != getWorkbenchWindow();
1008        boolean editorDropOK = ((sourcePart instanceof EditorPane) &&
1009                                    sourcePart.getWorkbenchWindow().getWorkbench() ==
1010                                    getWorkbenchWindow().getWorkbench());
1011        if (differentWindows && !editorDropOK) {
1012            return null;
1013        }
1014
1015        Rectangle containerBounds = DragUtil.getDisplayBounds(parent);
1016        LayoutPart targetPart = null;
1017        ILayoutContainer sourceContainer = isStackType(sourcePart) ? (ILayoutContainer) sourcePart
1018                : sourcePart.getContainer();
1019
1020        // If this container has no visible children
1021
if (getVisibleChildrenCount(this) == 0) {
1022            return createDropTarget(sourcePart, SWT.CENTER, SWT.CENTER, null);
1023        }
1024        
1025        if (containerBounds.contains(position)) {
1026
1027            if (root != null) {
1028                targetPart = root.findPart(parent.toControl(position));
1029            }
1030
1031            if (targetPart != null) {
1032                final Control targetControl = targetPart.getControl();
1033
1034                final Rectangle targetBounds = DragUtil
1035                        .getDisplayBounds(targetControl);
1036
1037                int side = Geometry.getClosestSide(targetBounds, position);
1038                int distance = Geometry.getDistanceFromEdge(targetBounds, position, side);
1039               
1040                // is the source coming from a standalone part
1041
boolean standalone = (isStackType(sourcePart)
1042                        && ((PartStack) sourcePart).isStandalone())
1043                    || (isPaneType(sourcePart)
1044                            && ((PartPane) sourcePart).getStack()!=null
1045                            && ((PartPane) sourcePart).getStack().isStandalone());
1046                
1047                // Only allow dropping onto an existing stack from different windows
1048
if (differentWindows && targetPart instanceof EditorStack) {
1049                    IDropTarget target = targetPart.getDropTarget(draggedObject, position);
1050                    return target;
1051                }
1052                
1053                // Reserve the 5 pixels around the edge of the part for the drop-on-edge cursor
1054
if (distance >= 5 && !standalone) {
1055                    // Otherwise, ask the part if it has any special meaning for this drop location
1056
IDropTarget target = targetPart.getDropTarget(draggedObject, position);
1057                    if (target != null) {
1058                        return target;
1059                    }
1060                }
1061                
1062                if (distance > 30 && isStackType(targetPart) && !standalone) {
1063                    if (targetPart instanceof ILayoutContainer) {
1064                        ILayoutContainer targetContainer = (ILayoutContainer)targetPart;
1065                        if (targetContainer.allowsAdd(sourcePart)) {
1066                            side = SWT.CENTER;
1067                        }
1068                    }
1069                }
1070                
1071                // If the part doesn't want to override this drop location then drop on the edge
1072

1073                // A "pointless drop" would be one that will put the dragged object back where it started.
1074
// Note that it should be perfectly valid to drag an object back to where it came from -- however,
1075
// the drop should be ignored.
1076

1077                boolean pointlessDrop = isZoomed();
1078
1079                if (sourcePart == targetPart) {
1080                    pointlessDrop = true;
1081                }
1082
1083                if ((sourceContainer != null)
1084                        && (sourceContainer == targetPart)
1085                        && getVisibleChildrenCount(sourceContainer) <= 1) {
1086                    pointlessDrop = true;
1087                }
1088
1089                if (side == SWT.CENTER
1090                        && sourcePart.getContainer() == targetPart) {
1091                    pointlessDrop = true;
1092                }
1093
1094                int cursor = side;
1095
1096                if (pointlessDrop) {
1097                    side = SWT.NONE;
1098                    cursor = SWT.CENTER;
1099                }
1100
1101                return createDropTarget(sourcePart, side, cursor, targetPart);
1102            }
1103        } else {
1104            // We only allow dropping into a stack, not creating one
1105
if (differentWindows)
1106                return null;
1107            
1108            int side = Geometry.getClosestSide(containerBounds, position);
1109
1110            boolean pointlessDrop = isZoomed();
1111
1112            if ((isStackType(sourcePart) && sourcePart.getContainer() == this)
1113                    || (sourcePart.getContainer() != null
1114                       && isPaneType(sourcePart)
1115                       && getVisibleChildrenCount(sourcePart.getContainer()) <= 1)
1116                       && ((LayoutPart)sourcePart.getContainer()).getContainer() == this) {
1117                if (root == null || getVisibleChildrenCount(this) <= 1) {
1118                    pointlessDrop = true;
1119                }
1120            }
1121
1122            int cursor = Geometry.getOppositeSide(side);
1123
1124            if (pointlessDrop) {
1125                side = SWT.NONE;
1126            }
1127
1128            return createDropTarget(sourcePart, side, cursor, null);
1129        }
1130
1131        return null;
1132    }
1133
1134    /**
1135     * @param sourcePart
1136     * @param targetPart
1137     * @param side
1138     * @param cursor
1139     * @return
1140     * @since 3.1
1141     */

1142    private SashContainerDropTarget createDropTarget(final LayoutPart sourcePart, int side, int cursor, LayoutPart targetPart) {
1143        if (dropTarget == null) {
1144            dropTarget = new SashContainerDropTarget(sourcePart, side, cursor,
1145                targetPart);
1146        } else {
1147            dropTarget.setTarget(sourcePart, side, cursor, targetPart);
1148        }
1149        return dropTarget;
1150    }
1151
1152    /**
1153     * Returns true iff this PartSashContainer allows its parts to be stacked onto the given
1154     * container.
1155     *
1156     * @param container
1157     * @return
1158     */

1159    public abstract boolean isStackType(LayoutPart toTest);
1160
1161    public abstract boolean isPaneType(LayoutPart toTest);
1162
1163    /* (non-Javadoc)
1164     * @see org.eclipse.ui.internal.PartSashContainer#dropObject(org.eclipse.ui.internal.LayoutPart, org.eclipse.ui.internal.LayoutPart, int)
1165     */

1166    protected void dropObject(PartPane[] toDrop, LayoutPart visiblePart,
1167            LayoutPart targetPart, int side) {
1168        getControl().setRedraw(false);
1169
1170        // Targetpart is null if there isn't a part under the cursor (all the parts are
1171
// hidden or the container is empty). In this case, the actual side doesn't really
1172
// since we'll be the only visible container and will fill the entire space. However,
1173
// we can't leave it as SWT.CENTER since we can't stack if we don't have something
1174
// to stack on. In this case, we pick SWT.BOTTOM -- this will insert the new pane
1175
// below any currently-hidden parts.
1176
if (targetPart == null && side == SWT.CENTER) {
1177            side = SWT.BOTTOM;
1178        }
1179        
1180        if (side == SWT.CENTER) {
1181            if (isStackType(targetPart)) {
1182                PartStack stack = (PartStack) targetPart;
1183                for (int idx = 0; idx < toDrop.length; idx++) {
1184                    PartPane next = toDrop[idx];
1185                    stack(next, stack);
1186                }
1187            }
1188        } else {
1189            PartStack newPart = createStack();
1190
1191            // if the toDrop array has 1 item propogate the stack
1192
// appearance
1193
if (toDrop.length == 1 && toDrop[0].getStack()!=null) {
1194                toDrop[0].getStack().copyAppearanceProperties(newPart);
1195            }
1196            
1197            for (int idx = 0; idx < toDrop.length; idx++) {
1198                PartPane next = toDrop[idx];
1199                stack(next, newPart);
1200            }
1201
1202            addEnhanced(newPart, side, getDockingRatio(newPart, targetPart),
1203                    targetPart);
1204        }
1205
1206        if (visiblePart != null) {
1207            setVisiblePart(visiblePart.getContainer(), visiblePart);
1208        }
1209
1210        getControl().setRedraw(true);
1211        
1212        if (visiblePart != null) {
1213            visiblePart.setFocus();
1214        }
1215    }
1216
1217    protected abstract PartStack createStack();
1218
1219    public void stack(LayoutPart newPart, ILayoutContainer container) {
1220        getControl().setRedraw(false);
1221
1222        // Only deref the part if it is being referenced in -this- perspective
1223
Perspective persp = page.getActivePerspective();
1224        PerspectiveHelper pres = (persp != null) ? persp.getPresentation() : null;
1225        if (pres != null && newPart instanceof ViewPane) {
1226            ViewPane vp = (ViewPane) newPart;
1227            IViewReference vRef = vp.getViewReference();
1228            LayoutPart fpp = pres.findPart(vRef.getId(), vRef.getSecondaryId());
1229            
1230            if (fpp != null) {
1231                // Remove the part from old container.
1232
derefPart(newPart);
1233            }
1234        }
1235        else {
1236            // Remove the part from old container.
1237
derefPart(newPart);
1238        }
1239        
1240        // Reparent part and add it to the workbook
1241
newPart.reparent(getParent());
1242        container.add(newPart);
1243        getControl().setRedraw(true);
1244
1245    }
1246
1247    /**
1248     * @param container
1249     * @param visiblePart
1250     */

1251    protected abstract void setVisiblePart(ILayoutContainer container,
1252            LayoutPart visiblePart);
1253
1254    /**
1255     * @param container
1256     * @return
1257     */

1258    protected abstract LayoutPart getVisiblePart(ILayoutContainer container);
1259
1260    /**
1261     * @param sourcePart
1262     */

1263    protected void derefPart(LayoutPart sourcePart) {
1264        ILayoutContainer container = sourcePart.getContainer();
1265        if (container != null) {
1266            container.remove(sourcePart);
1267        }
1268
1269        if (container instanceof LayoutPart) {
1270            if (isStackType((LayoutPart) container)) {
1271                PartStack stack = (PartStack) container;
1272                if (stack.getChildren().length == 0) {
1273                    remove(stack);
1274                    stack.dispose();
1275                }
1276            }
1277        }
1278    }
1279
1280    protected int getVisibleChildrenCount(ILayoutContainer container) {
1281        // Treat null as an empty container
1282
if (container == null) {
1283            return 0;
1284        }
1285
1286        LayoutPart[] children = container.getChildren();
1287
1288        int count = 0;
1289        for (int idx = 0; idx < children.length; idx++) {
1290            if (!(children[idx] instanceof PartPlaceholder)) {
1291                count++;
1292            }
1293        }
1294
1295        return count;
1296    }
1297
1298    protected float getDockingRatio(LayoutPart dragged, LayoutPart target) {
1299        return 0.5f;
1300    }
1301
1302    /**
1303     * Writes a description of the layout to the given string buffer.
1304     * This is used for drag-drop test suites to determine if two layouts are the
1305     * same. Like a hash code, the description should compare as equal iff the
1306     * layouts are the same. However, it should be user-readable in order to
1307     * help debug failed tests. Although these are english readable strings,
1308     * they should not be translated or equality tests will fail.
1309     *
1310     * @param buf
1311     */

1312    public void describeLayout(StringBuffer JavaDoc buf) {
1313        if (root == null) {
1314            return;
1315        }
1316
1317        if (isZoomed()) {
1318            buf.append("zoomed "); //$NON-NLS-1$
1319
root.describeLayout(buf);
1320        } else {
1321            buf.append("layout "); //$NON-NLS-1$
1322
root.describeLayout(buf);
1323        }
1324    }
1325
1326    /**
1327     * Adds a new child to the container relative to some part
1328     *
1329     * @param child
1330     * @param relationship
1331     * @param left preferred pixel size of the left/top child
1332     * @param right preferred pixel size of the right/bottom child
1333     * @param relative relative part
1334     */

1335    void add(LayoutPart child, int relationship, int left, int right,
1336            LayoutPart relative) {
1337
1338        if (child == null) {
1339            return;
1340        }
1341        if (relative != null && !isChild(relative)) {
1342            return;
1343        }
1344        if (relationship < IPageLayout.LEFT
1345                || relationship > IPageLayout.BOTTOM) {
1346            relationship = IPageLayout.LEFT;
1347        }
1348
1349        // store info about relative positions
1350
RelationshipInfo info = new RelationshipInfo();
1351        info.part = child;
1352        info.relationship = relationship;
1353        info.left = left;
1354        info.right = right;
1355        info.relative = relative;
1356        addChild(info);
1357    }
1358
1359    /* (non-Javadoc)
1360     * @see org.eclipse.ui.internal.ILayoutContainer#isZoomed(org.eclipse.ui.internal.LayoutPart)
1361     */

1362    public boolean childIsZoomed(LayoutPart toTest) {
1363        return toTest == getZoomedPart();
1364    }
1365    
1366    /* (non-Javadoc)
1367     * @see org.eclipse.ui.internal.ILayoutContainer#allowsAutoFocus()
1368     */

1369    public boolean allowsAutoFocus() {
1370        return true;
1371    }
1372    
1373    /* (non-Javadoc)
1374     * @see org.eclipse.ui.internal.LayoutPart#startDeferringEvents()
1375     */

1376    protected void startDeferringEvents() {
1377        super.startDeferringEvents();
1378        
1379        LayoutPart[] deferredChildren = (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
1380        for (int i = 0; i < deferredChildren.length; i++) {
1381            LayoutPart child = deferredChildren[i];
1382            
1383            child.deferUpdates(true);
1384        }
1385    }
1386    
1387    /* (non-Javadoc)
1388     * @see org.eclipse.ui.internal.LayoutPart#handleDeferredEvents()
1389     */

1390    protected void handleDeferredEvents() {
1391        super.handleDeferredEvents();
1392        
1393        LayoutPart[] deferredChildren = (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
1394        for (int i = 0; i < deferredChildren.length; i++) {
1395            LayoutPart child = deferredChildren[i];
1396        
1397            child.deferUpdates(false);
1398        }
1399    }
1400    
1401    /* (non-Javadoc)
1402     * @see org.eclipse.ui.internal.LayoutPart#testInvariants()
1403     */

1404    public void testInvariants() {
1405        super.testInvariants();
1406
1407        // If we have a parent container, ensure that we are displaying the zoomed appearance iff
1408
// our parent is zoomed in on us
1409
if (getContainer() != null) {
1410            Assert.isTrue((getZoomedPart() != null) == (getContainer().childIsZoomed(this)));
1411        }
1412        
1413        LayoutPart[] childArray = getChildren();
1414
1415        for (int idx = 0; idx < childArray.length; idx++) {
1416            childArray[idx].testInvariants();
1417        }
1418        
1419        // If we're zoomed, ensure that we're actually zoomed into one of our children
1420
if (isZoomed()) {
1421            Assert.isTrue(children.contains(zoomedPart));
1422        }
1423    }
1424}
1425
Popular Tags