KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2004, 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  * Chris Gross chris.gross@us.ibm.com Bug 107443
11  *******************************************************************************/

12 package org.eclipse.ui.internal;
13
14 import java.util.ArrayList JavaDoc;
15 import java.util.Arrays JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Map JavaDoc;
21 import java.util.Set JavaDoc;
22
23 import org.eclipse.core.runtime.Assert;
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.core.runtime.ListenerList;
26 import org.eclipse.core.runtime.Status;
27 import org.eclipse.jface.action.ContributionItem;
28 import org.eclipse.jface.action.IMenuManager;
29 import org.eclipse.jface.preference.IPreferenceStore;
30 import org.eclipse.jface.util.Geometry;
31 import org.eclipse.osgi.util.NLS;
32 import org.eclipse.swt.graphics.Cursor;
33 import org.eclipse.swt.graphics.Point;
34 import org.eclipse.swt.graphics.Rectangle;
35 import org.eclipse.swt.widgets.Composite;
36 import org.eclipse.swt.widgets.Control;
37 import org.eclipse.swt.widgets.Display;
38 import org.eclipse.ui.IEditorInput;
39 import org.eclipse.ui.IMemento;
40 import org.eclipse.ui.IPersistable;
41 import org.eclipse.ui.IPropertyListener;
42 import org.eclipse.ui.IWorkbenchPartReference;
43 import org.eclipse.ui.IWorkbenchPreferenceConstants;
44 import org.eclipse.ui.PartInitException;
45 import org.eclipse.ui.PlatformUI;
46 import org.eclipse.ui.XMLMemento;
47 import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
48 import org.eclipse.ui.internal.dnd.AbstractDropTarget;
49 import org.eclipse.ui.internal.dnd.DragUtil;
50 import org.eclipse.ui.internal.dnd.IDropTarget;
51 import org.eclipse.ui.internal.dnd.SwtUtil;
52 import org.eclipse.ui.internal.intro.IIntroConstants;
53 import org.eclipse.ui.internal.layout.ITrimManager;
54 import org.eclipse.ui.internal.layout.IWindowTrim;
55 import org.eclipse.ui.internal.presentations.PresentablePart;
56 import org.eclipse.ui.internal.presentations.PresentationFactoryUtil;
57 import org.eclipse.ui.internal.presentations.PresentationSerializer;
58 import org.eclipse.ui.internal.util.PrefUtil;
59 import org.eclipse.ui.internal.util.Util;
60 import org.eclipse.ui.presentations.AbstractPresentationFactory;
61 import org.eclipse.ui.presentations.IPresentablePart;
62 import org.eclipse.ui.presentations.IStackPresentationSite;
63 import org.eclipse.ui.presentations.StackDropResult;
64 import org.eclipse.ui.presentations.StackPresentation;
65
66 /**
67  * Implements the common behavior for stacks of Panes (ie: EditorStack and ViewStack)
68  * This layout container has PartPanes as children and belongs to a PartSashContainer.
69  *
70  * @since 3.0
71  */

72 public abstract class PartStack extends LayoutPart implements ILayoutContainer {
73
74     public static final int PROP_SELECTION = 0x42;
75     
76     private List JavaDoc children = new ArrayList JavaDoc(3);
77     private boolean isActive = true;
78     private ArrayList JavaDoc presentableParts = new ArrayList JavaDoc();
79     
80     private Map JavaDoc properties = new HashMap JavaDoc();
81     
82     protected int appearance = PresentationFactoryUtil.ROLE_VIEW;
83     
84     /**
85      * Stores the last value passed to setSelection. If UI updates are being deferred,
86      * this may be significantly different from the other current pointers. Once UI updates
87      * are re-enabled, the stack will update the presentation selection to match the requested
88      * current pointer.
89      */

90     private LayoutPart requestedCurrent;
91     
92     /**
93      * Stores the current part for the stack. Whenever the outside world asks a PartStack
94      * for the current part, this is what gets returned. This pointer is only updated after
95      * the presentation selection has been restored and the stack has finished updating its
96      * internal state. If the stack is still in the process of updating the presentation,
97      * it will still point to the previous part until the presentation is up-to-date.
98      */

99     private LayoutPart current;
100     
101     /**
102      * Stores the presentable part sent to the presentation. Whenever the presentation
103      * asks for the current part, this is what gets returned. This is updated before sending
104      * the part to the presentation, and it is not updated while UI updates are disabled.
105      * When UI updates are enabled, the stack first makes presentationCurrent match
106      * requestedCurrent. Once the presentation is displaying the correct part, the "current"
107      * pointer on PartStack is updated.
108      */

109     private PresentablePart presentationCurrent;
110
111     private boolean ignoreSelectionChanges = false;
112
113     protected IMemento savedPresentationState = null;
114
115     protected DefaultStackPresentationSite presentationSite = new DefaultStackPresentationSite() {
116
117         public void close(IPresentablePart part) {
118             PartStack.this.close(part);
119         }
120
121         public void close(IPresentablePart[] parts) {
122             PartStack.this.close(parts);
123         }
124
125         public void dragStart(IPresentablePart beingDragged,
126                 Point initialLocation, boolean keyboard) {
127             PartStack.this.dragStart(beingDragged, initialLocation, keyboard);
128         }
129
130         public void dragStart(Point initialLocation, boolean keyboard) {
131             PartStack.this.dragStart(null, initialLocation, keyboard);
132         }
133
134         public boolean isPartMoveable(IPresentablePart part) {
135             return PartStack.this.isMoveable(part);
136         }
137
138         public void selectPart(IPresentablePart toSelect) {
139             PartStack.this.presentationSelectionChanged(toSelect);
140         }
141
142         public boolean supportsState(int state) {
143             return PartStack.this.supportsState(state);
144         }
145
146         public void setState(int newState) {
147             PartStack.this.setState(newState);
148         }
149
150         public IPresentablePart getSelectedPart() {
151             return PartStack.this.getSelectedPart();
152         }
153
154         public void addSystemActions(IMenuManager menuManager) {
155             PartStack.this.addSystemActions(menuManager);
156         }
157
158         public boolean isStackMoveable() {
159             return canMoveFolder();
160         }
161         
162         public void flushLayout() {
163             PartStack.this.flushLayout();
164         }
165
166         public IPresentablePart[] getPartList() {
167             List JavaDoc parts = getPresentableParts();
168             
169             return (IPresentablePart[]) parts.toArray(new IPresentablePart[parts.size()]);
170         }
171
172         public String JavaDoc getProperty(String JavaDoc id) {
173             return PartStack.this.getProperty(id);
174         }
175     };
176
177     private static final class PartStackDropResult extends AbstractDropTarget {
178         private PartPane pane;
179         
180         // Result of the presentation's dragOver method or null if we are stacking over the
181
// client area of the pane.
182
private StackDropResult dropResult;
183         private PartStack stack;
184         
185         /**
186          * Resets the target of this drop result (allows the same drop result object to be
187          * reused)
188          *
189          * @param stack
190          * @param pane
191          * @param result result of the presentation's dragOver method, or null if we are
192          * simply stacking anywhere.
193          * @since 3.1
194          */

195         public void setTarget(PartStack stack, PartPane pane, StackDropResult result) {
196             this.pane = pane;
197             this.dropResult = result;
198             this.stack = stack;
199         }
200         
201         public void drop() {
202             // If we're dragging a pane over itself do nothing
203
//if (dropResult.getInsertionPoint() == pane.getPresentablePart()) { return; };
204

205             Object JavaDoc cookie = null;
206             if (dropResult != null) {
207                 cookie = dropResult.getCookie();
208             }
209
210             // Handle cross window drops by opening a new editor
211
if (pane instanceof EditorPane) {
212                 if (pane.getWorkbenchWindow() != stack.getWorkbenchWindow()) {
213                     EditorPane editor = (EditorPane) pane;
214                     try {
215                         IEditorInput input = editor.getEditorReference().getEditorInput();
216                         
217                         // Close the old editor and capture the actual closed state incase of a 'cancel'
218
boolean editorClosed = editor.getPage().closeEditor(editor.getEditorReference(), true);
219                         
220                         // Only open open the new editor if the old one closed
221
if (editorClosed)
222                             stack.getPage().openEditor(input, editor.getEditorReference().getId());
223                         return;
224                     } catch (PartInitException e) {
225                         e.printStackTrace();
226                     }
227                     
228                 }
229             }
230             
231             if (pane.getContainer() != stack) {
232                 // Moving from another stack
233
stack.derefPart(pane);
234                 pane.reparent(stack.getParent());
235                 stack.add(pane, cookie);
236                 stack.setSelection(pane);
237                 pane.setFocus();
238             } else if (cookie != null) {
239                 // Rearranging within this stack
240
stack.getPresentation().movePart(stack.getPresentablePart(pane), cookie);
241             }
242         }
243
244         public Cursor getCursor() {
245             return DragCursors.getCursor(DragCursors.CENTER);
246         }
247
248         public Rectangle getSnapRectangle() {
249             if (dropResult == null) {
250                 return DragUtil.getDisplayBounds(stack.getControl());
251             }
252             return dropResult.getSnapRectangle();
253         }
254     }
255
256     private static final PartStackDropResult dropResult = new PartStackDropResult();
257
258     protected boolean isMinimized;
259
260     private ListenerList listeners = new ListenerList();
261
262     /**
263      * Custom presentation factory to use for this stack, or null to
264      * use the default
265      */

266     private AbstractPresentationFactory factory;
267
268     private boolean smartZoomed = false;
269     private boolean doingUnzoom = false;
270             
271     protected abstract boolean isMoveable(IPresentablePart part);
272
273     protected abstract void addSystemActions(IMenuManager menuManager);
274
275     protected abstract boolean supportsState(int newState);
276
277     protected abstract boolean canMoveFolder();
278
279     protected abstract void derefPart(LayoutPart toDeref);
280
281     protected abstract boolean allowsDrop(PartPane part);
282
283     protected static void appendToGroupIfPossible(IMenuManager m,
284             String JavaDoc groupId, ContributionItem item) {
285         try {
286             m.appendToGroup(groupId, item);
287         } catch (IllegalArgumentException JavaDoc e) {
288             m.add(item);
289         }
290     }
291     
292     /**
293      * Creates a new PartStack, given a constant determining which presentation to use
294      *
295      * @param appearance one of the PresentationFactoryUtil.ROLE_* constants
296      */

297     public PartStack(int appearance) {
298         this(appearance, null);
299     }
300     
301     /**
302      * Creates a new part stack that uses the given custom presentation factory
303      * @param appearance
304      * @param factory custom factory to use (or null to use the default)
305      */

306     public PartStack(int appearance, AbstractPresentationFactory factory) {
307         super("PartStack"); //$NON-NLS-1$
308

309         this.appearance = appearance;
310         this.factory = factory;
311     }
312
313     /**
314      * Adds a property listener to this stack. The listener will receive a PROP_SELECTION
315      * event whenever the result of getSelection changes
316      *
317      * @param listener
318      */

319     public void addListener(IPropertyListener listener) {
320         listeners.add(listener);
321     }
322     
323     public void removeListener(IPropertyListener listener) {
324         listeners.remove(listener);
325     }
326     
327     protected final boolean isStandalone() {
328         return (appearance == PresentationFactoryUtil.ROLE_STANDALONE
329              || appearance == PresentationFactoryUtil.ROLE_STANDALONE_NOTITLE);
330     }
331     
332     /**
333      * Returns the currently selected IPresentablePart, or null if none
334      *
335      * @return
336      */

337     protected IPresentablePart getSelectedPart() {
338         return presentationCurrent;
339     }
340
341     protected IStackPresentationSite getPresentationSite() {
342         return presentationSite;
343     }
344
345     /**
346      * Tests the integrity of this object. Throws an exception if the object's state
347      * is invalid. For use in test suites.
348      */

349     public void testInvariants() {
350         Control focusControl = Display.getCurrent().getFocusControl();
351
352         boolean currentFound = false;
353
354         LayoutPart[] children = getChildren();
355
356         for (int idx = 0; idx < children.length; idx++) {
357             LayoutPart child = children[idx];
358
359             // No null children allowed
360
Assert.isNotNull(child,
361                     "null children are not allowed in PartStack"); //$NON-NLS-1$
362

363             // This object can only contain placeholders or PartPanes
364
Assert.isTrue(child instanceof PartPlaceholder
365                     || child instanceof PartPane,
366                     "PartStack can only contain PartPlaceholders or PartPanes"); //$NON-NLS-1$
367

368             // Ensure that all the PartPanes have an associated presentable part
369
IPresentablePart part = getPresentablePart(child);
370             if (child instanceof PartPane) {
371                 Assert.isNotNull(part,
372                         "All PartPanes must have a non-null IPresentablePart"); //$NON-NLS-1$
373
}
374
375             // Ensure that the child's backpointer points to this stack
376
ILayoutContainer childContainer = child.getContainer();
377
378             // Disable tests for placeholders -- PartPlaceholder backpointers don't
379
// obey the usual rules -- they sometimes point to a container placeholder
380
// for this stack instead of the real stack.
381
if (!(child instanceof PartPlaceholder)) {
382
383                 if (isDisposed()) {
384
385                     // Currently, we allow null backpointers if the widgetry is disposed.
386
// However, it is never valid for the child to have a parent other than
387
// this object
388
if (childContainer != null) {
389                         Assert
390                                 .isTrue(childContainer == this,
391                                         "PartStack has a child that thinks it has a different parent"); //$NON-NLS-1$
392
}
393                 } else {
394                     // If the widgetry exists, the child's backpointer must point to us
395
Assert
396                             .isTrue(childContainer == this,
397                                     "PartStack has a child that thinks it has a different parent"); //$NON-NLS-1$
398

399                     // If this child has focus, then ensure that it is selected and that we have
400
// the active appearance.
401

402                     if (SwtUtil.isChild(child.getControl(), focusControl)) {
403                         Assert.isTrue(child == current,
404                                 "The part with focus is not the selected part"); //$NON-NLS-1$
405
// focus check commented out since it fails when focus workaround in LayoutPart.setVisible is not present
406
// Assert.isTrue(getActive() == StackPresentation.AS_ACTIVE_FOCUS);
407
}
408                 }
409             }
410
411             // Ensure that "current" points to a valid child
412
if (child == current) {
413                 currentFound = true;
414             }
415
416             // Test the child's internal state
417
child.testInvariants();
418         }
419
420         // If we have at least one child, ensure that the "current" pointer points to one of them
421
if (!isDisposed() && getPresentableParts().size() > 0) {
422             Assert.isTrue(currentFound);
423
424             if (!isDisposed()) {
425                 StackPresentation presentation = getPresentation();
426
427                 // If the presentation controls have focus, ensure that we have the active appearance
428
if (SwtUtil.isChild(presentation.getControl(), focusControl)) {
429                     Assert
430                             .isTrue(
431                                     getActive() == StackPresentation.AS_ACTIVE_FOCUS,
432                                     "The presentation has focus but does not have the active appearance"); //$NON-NLS-1$
433
}
434             }
435         }
436         
437         // Check to that we're displaying the zoomed icon iff we're actually maximized
438
Assert.isTrue((getState() == IStackPresentationSite.STATE_MAXIMIZED)
439                 == (getContainer() != null && getContainer().childIsZoomed(this)));
440
441     }
442
443     /* (non-Javadoc)
444      * @see org.eclipse.ui.internal.LayoutPart#describeLayout(java.lang.StringBuffer)
445      */

446     public void describeLayout(StringBuffer JavaDoc buf) {
447         int activeState = getActive();
448         if (activeState == StackPresentation.AS_ACTIVE_FOCUS) {
449             buf.append("active "); //$NON-NLS-1$
450
} else if (activeState == StackPresentation.AS_ACTIVE_NOFOCUS) {
451             buf.append("active_nofocus "); //$NON-NLS-1$
452
}
453
454         buf.append("("); //$NON-NLS-1$
455

456         LayoutPart[] children = ((ILayoutContainer) this).getChildren();
457
458         int visibleChildren = 0;
459
460         for (int idx = 0; idx < children.length; idx++) {
461
462             LayoutPart next = children[idx];
463             if (!(next instanceof PartPlaceholder)) {
464                 if (idx > 0) {
465                     buf.append(", "); //$NON-NLS-1$
466
}
467
468                 if (next == requestedCurrent) {
469                     buf.append("*"); //$NON-NLS-1$
470
}
471
472                 next.describeLayout(buf);
473
474                 visibleChildren++;
475             }
476         }
477
478         buf.append(")"); //$NON-NLS-1$
479
}
480
481     /**
482      * See IVisualContainer#add
483      */

484     public void add(LayoutPart child) {
485         add(child, null);
486     }
487
488     /**
489      * Add a part at a particular position
490      */

491     protected void add(LayoutPart newChild, Object JavaDoc cookie) {
492         children.add(newChild);
493         
494         // Fix for bug 78470:
495
if(!(newChild.getContainer() instanceof ContainerPlaceholder)) {
496             newChild.setContainer(this);
497         }
498         
499         showPart(newChild, cookie);
500     }
501
502     public boolean allowsAdd(LayoutPart toAdd) {
503         return !isStandalone();
504     }
505     
506     /*
507      * (non-Javadoc)
508      *
509      * @see org.eclipse.ui.internal.ILayoutContainer#allowsAutoFocus()
510      */

511     public boolean allowsAutoFocus() {
512         if (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED) {
513             return false;
514         }
515
516         return super.allowsAutoFocus();
517     }
518
519     /**
520      * @param parts
521      */

522     protected void close(IPresentablePart[] parts) {
523         for (int idx = 0; idx < parts.length; idx++) {
524             IPresentablePart part = parts[idx];
525
526             close(part);
527         }
528     }
529
530     /**
531      * @param part
532      */

533     protected void close(IPresentablePart part) {
534         if (!presentationSite.isCloseable(part)) {
535             return;
536         }
537
538         LayoutPart layoutPart = getPaneFor(part);
539
540         if (layoutPart != null && layoutPart instanceof PartPane) {
541             PartPane viewPane = (PartPane) layoutPart;
542
543             viewPane.doHide();
544         }
545     }
546
547     public boolean isDisposed() {
548         return getPresentation() == null;
549     }
550
551     protected AbstractPresentationFactory getFactory() {
552         
553         if (factory != null) {
554             return factory;
555         }
556         
557         return ((WorkbenchWindow) getPage()
558                 .getWorkbenchWindow()).getWindowConfigurer()
559                 .getPresentationFactory();
560     }
561     
562     public void createControl(Composite parent) {
563         if (!isDisposed()) {
564             return;
565         }
566
567         AbstractPresentationFactory factory = getFactory();
568
569         PresentationSerializer serializer = new PresentationSerializer(
570                 getPresentableParts());
571
572         StackPresentation presentation = PresentationFactoryUtil
573                 .createPresentation(factory, appearance, parent,
574                         presentationSite, serializer, savedPresentationState);
575
576         createControl(parent, presentation);
577         getControl().moveBelow(null);
578     }
579
580     /* (non-Javadoc)
581      * @see org.eclipse.ui.internal.LayoutPart#getDropTarget(java.lang.Object, org.eclipse.swt.graphics.Point)
582      */

583     public IDropTarget getDropTarget(Object JavaDoc draggedObject, Point position) {
584
585         if (!(draggedObject instanceof PartPane)) {
586             return null;
587         }
588
589         final PartPane pane = (PartPane) draggedObject;
590         if (isStandalone()
591                 || !allowsDrop(pane)) {
592             return null;
593         }
594
595         // Don't allow views to be dragged between windows
596
boolean differentWindows = pane.getWorkbenchWindow() != getWorkbenchWindow();
597         boolean editorDropOK = ((pane instanceof EditorPane) &&
598                 pane.getWorkbenchWindow().getWorkbench() ==
599                     getWorkbenchWindow().getWorkbench());
600         if (differentWindows && !editorDropOK) {
601             return null;
602         }
603
604         StackDropResult dropResult = getPresentation().dragOver(
605                 getControl(), position);
606         
607         if (dropResult == null) {
608             return null;
609         }
610         
611         return createDropTarget(pane, dropResult);
612     }
613     
614     public void setActive(boolean isActive) {
615  
616         this.isActive = isActive;
617         // Add all visible children to the presentation
618
Iterator JavaDoc iter = children.iterator();
619         while (iter.hasNext()) {
620             LayoutPart part = (LayoutPart) iter.next();
621             
622             part.setContainer(isActive ? this : null);
623         }
624         
625         for (Iterator JavaDoc iterator = presentableParts.iterator(); iterator.hasNext();) {
626             PresentablePart next = (PresentablePart) iterator.next();
627             
628             next.enableInputs(isActive);
629             next.enableOutputs(isActive);
630         }
631     }
632     
633     public void createControl(Composite parent, StackPresentation presentation) {
634
635         Assert.isTrue(isDisposed());
636
637         if (presentationSite.getPresentation() != null) {
638             return;
639         }
640
641         presentationSite.setPresentation(presentation);
642
643         // Add all visible children to the presentation
644
// Use a copy of the current set of children to avoid a ConcurrentModificationException
645
// if a part is added to the same stack while iterating over the children (bug 78470)
646
LayoutPart[] childParts = (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
647         for (int i = 0; i < childParts.length; i++) {
648             LayoutPart part = childParts[i];
649             showPart(part, null);
650         }
651         
652         if (savedPresentationState!=null) {
653             PresentationSerializer serializer = new PresentationSerializer(
654                     getPresentableParts());
655             presentation.restoreState(serializer, savedPresentationState);
656         }
657
658         Control ctrl = getPresentation().getControl();
659
660         ctrl.setData(this);
661
662         // We should not have a placeholder selected once we've created the widgetry
663
if (requestedCurrent instanceof PartPlaceholder) {
664             requestedCurrent = null;
665             updateContainerVisibleTab();
666         }
667
668         refreshPresentationSelection();
669     }
670
671     public IDropTarget createDropTarget(PartPane pane, StackDropResult result) {
672         dropResult.setTarget(this, pane, result);
673         return dropResult;
674     }
675     
676     /**
677      * Saves the current state of the presentation to savedPresentationState, if the
678      * presentation exists.
679      */

680     protected void savePresentationState() {
681         if (isDisposed()) {
682             return;
683         }
684
685         {// Save the presentation's state before disposing it
686
XMLMemento memento = XMLMemento
687                     .createWriteRoot(IWorkbenchConstants.TAG_PRESENTATION);
688             memento.putString(IWorkbenchConstants.TAG_ID, getFactory().getId());
689
690             PresentationSerializer serializer = new PresentationSerializer(
691                     getPresentableParts());
692
693             getPresentation().saveState(serializer, memento);
694
695             // Store the memento in savedPresentationState
696
savedPresentationState = memento;
697         }
698     }
699
700     /**
701      * See LayoutPart#dispose
702      */

703     public void dispose() {
704
705         if (isDisposed()) {
706             return;
707         }
708
709         savePresentationState();
710
711         presentationSite.dispose();
712         
713         for (Iterator JavaDoc iter = presentableParts.iterator(); iter.hasNext();) {
714             PresentablePart part = (PresentablePart) iter.next();
715             
716             part.dispose();
717         }
718         presentableParts.clear();
719         
720         presentationCurrent = null;
721         current = null;
722         fireInternalPropertyChange(PROP_SELECTION);
723     }
724
725     public void findSashes(LayoutPart part, PartPane.Sashes sashes) {
726         ILayoutContainer container = getContainer();
727
728         if (container != null) {
729             container.findSashes(this, sashes);
730         }
731     }
732
733     /**
734      * Gets the presentation bounds.
735      */

736     public Rectangle getBounds() {
737         if (getPresentation() == null) {
738             return new Rectangle(0, 0, 0, 0);
739         }
740
741         return getPresentation().getControl().getBounds();
742     }
743
744     /**
745      * See IVisualContainer#getChildren
746      */

747     public LayoutPart[] getChildren() {
748         return (LayoutPart[]) children.toArray(new LayoutPart[children.size()]);
749     }
750
751     public Control getControl() {
752         StackPresentation presentation = getPresentation();
753
754         if (presentation == null) {
755             return null;
756         }
757
758         return presentation.getControl();
759     }
760
761     /**
762      * Answer the number of children.
763      */

764     public int getItemCount() {
765         if (isDisposed()) {
766             return children.size();
767         }
768         return getPresentableParts().size();
769     }
770     
771     /**
772      * Returns the LayoutPart for the given IPresentablePart, or null if the given
773      * IPresentablePart is not in this stack. Returns null if given a null argument.
774      *
775      * @param part to locate or null
776      * @return
777      */

778     protected LayoutPart getPaneFor(IPresentablePart part) {
779         if (part == null || !(part instanceof PresentablePart)) {
780             return null;
781         }
782
783         return ((PresentablePart)part).getPane();
784     }
785
786     /**
787      * Get the parent control.
788      */

789     public Composite getParent() {
790         return getControl().getParent();
791     }
792
793     /**
794      * Returns a list of IPresentablePart
795      *
796      * @return
797      */

798     public List JavaDoc getPresentableParts() {
799         return presentableParts;
800     }
801
802     private PresentablePart getPresentablePart(LayoutPart pane) {
803         for (Iterator JavaDoc iter = presentableParts.iterator(); iter.hasNext();) {
804             PresentablePart part = (PresentablePart) iter.next();
805             
806             if (part.getPane() == pane) {
807                 return part;
808             }
809         }
810         
811         return null;
812     }
813     
814     protected StackPresentation getPresentation() {
815         return presentationSite.getPresentation();
816     }
817
818     /**
819      * Returns the visible child.
820      * @return the currently visible part, or null if none
821      */

822     public PartPane getSelection() {
823         if (current instanceof PartPane) {
824             return (PartPane) current;
825         }
826         return null;
827     }
828
829     private void presentationSelectionChanged(IPresentablePart newSelection) {
830         // Ignore selection changes that occur as a result of removing a part
831
if (ignoreSelectionChanges) {
832             return;
833         }
834         LayoutPart newPart = getPaneFor(newSelection);
835
836         // This method should only be called on objects that are already in the layout
837
Assert.isNotNull(newPart);
838
839         if (newPart == requestedCurrent) {
840             return;
841         }
842
843         setSelection(newPart);
844
845         if (newPart != null) {
846             newPart.setFocus();
847         }
848
849     }
850
851     /**
852      * See IVisualContainer#remove
853      */

854     public void remove(LayoutPart child) {
855         PresentablePart presentablePart = getPresentablePart(child);
856
857         // Need to remove it from the list of children before notifying the presentation
858
// since it may setVisible(false) on the part, leading to a partHidden notification,
859
// during which findView must not find the view being removed. See bug 60039.
860
children.remove(child);
861
862         StackPresentation presentation = getPresentation();
863
864         if (presentablePart != null && presentation != null) {
865             ignoreSelectionChanges = true;
866             presentableParts .remove(presentablePart);
867             presentation.removePart(presentablePart);
868             presentablePart.dispose();
869             ignoreSelectionChanges = false;
870         }
871
872         if (!isDisposed()) {
873             child.setContainer(null);
874         }
875
876         if (child == requestedCurrent) {
877             updateContainerVisibleTab();
878         }
879     }
880
881     /**
882      * Reparent a part. Also reparent visible children...
883      */

884     public void reparent(Composite newParent) {
885
886         Control control = getControl();
887         if ((control == null) || (control.getParent() == newParent) || !control.isReparentable()) {
888             return;
889         }
890
891         super.reparent(newParent);
892
893         Iterator JavaDoc iter = children.iterator();
894         while (iter.hasNext()) {
895             LayoutPart next = (LayoutPart) iter.next();
896             next.reparent(newParent);
897         }
898     }
899
900     /**
901      * See IVisualContainer#replace
902      */

903     public void replace(LayoutPart oldChild, LayoutPart newChild) {
904         int idx = children.indexOf(oldChild);
905         int numPlaceholders = 0;
906         //subtract the number of placeholders still existing in the list
907
//before this one - they wont have parts.
908
for (int i = 0; i < idx; i++) {
909             if (children.get(i) instanceof PartPlaceholder) {
910                 numPlaceholders++;
911             }
912         }
913         Integer JavaDoc cookie = new Integer JavaDoc(idx - numPlaceholders);
914         children.add(idx, newChild);
915
916         showPart(newChild, cookie);
917
918         if (oldChild == requestedCurrent && !(newChild instanceof PartPlaceholder)) {
919             setSelection(newChild);
920         }
921
922         remove(oldChild);
923     }
924     
925     /* (non-Javadoc)
926      * @see org.eclipse.ui.internal.LayoutPart#computePreferredSize(boolean, int, int, int)
927      */

928     public int computePreferredSize(boolean width, int availableParallel,
929             int availablePerpendicular, int preferredParallel) {
930         
931         return getPresentation().computePreferredSize(width, availableParallel,
932                 availablePerpendicular, preferredParallel);
933     }
934     
935     /* (non-Javadoc)
936      * @see org.eclipse.ui.internal.LayoutPart#getSizeFlags(boolean)
937      */

938     public int getSizeFlags(boolean horizontal) {
939         StackPresentation presentation = getPresentation();
940         
941         if (presentation != null) {
942             return presentation.getSizeFlags(horizontal);
943         }
944         
945         return 0;
946     }
947     
948     /**
949      * @see IPersistable
950      */

951     public IStatus restoreState(IMemento memento) {
952         // Read the active tab.
953
String JavaDoc activeTabID = memento
954                 .getString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID);
955
956         // Read the page elements.
957
IMemento[] children = memento.getChildren(IWorkbenchConstants.TAG_PAGE);
958         if (children != null) {
959             // Loop through the page elements.
960
for (int i = 0; i < children.length; i++) {
961                 // Get the info details.
962
IMemento childMem = children[i];
963                 String JavaDoc partID = childMem
964                         .getString(IWorkbenchConstants.TAG_CONTENT);
965
966                 // Create the part.
967
LayoutPart part = new PartPlaceholder(partID);
968                 part.setContainer(this);
969                 add(part);
970                 //1FUN70C: ITPUI:WIN - Shouldn't set Container when not active
971
//part.setContainer(this);
972
if (partID.equals(activeTabID)) {
973                     setSelection(part);
974                     // Mark this as the active part.
975
//current = part;
976
}
977             }
978         }
979
980         IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
981         boolean useNewMinMax = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
982         final Integer JavaDoc expanded = memento.getInteger(IWorkbenchConstants.TAG_EXPANDED);
983         if (useNewMinMax && expanded != null) {
984             StartupThreading.runWithoutExceptions(new StartupRunnable() {
985                 public void runWithException() throws Throwable JavaDoc {
986                     setState((expanded == null || expanded.intValue() != IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_RESTORED
987                             : IStackPresentationSite.STATE_MINIMIZED);
988                 }
989             });
990         }
991         else {
992             setState((expanded == null || expanded.intValue() != IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_RESTORED
993                     : IStackPresentationSite.STATE_MINIMIZED);
994         }
995
996         Integer JavaDoc appearance = memento
997                 .getInteger(IWorkbenchConstants.TAG_APPEARANCE);
998         if (appearance != null) {
999             this.appearance = appearance.intValue();
1000        }
1001
1002        // Determine if the presentation has saved any info here
1003
savedPresentationState = null;
1004        IMemento[] presentationMementos = memento
1005                .getChildren(IWorkbenchConstants.TAG_PRESENTATION);
1006
1007        for (int idx = 0; idx < presentationMementos.length; idx++) {
1008            IMemento child = presentationMementos[idx];
1009
1010            String JavaDoc id = child.getString(IWorkbenchConstants.TAG_ID);
1011
1012            if (Util.equals(id, getFactory().getId())) {
1013                savedPresentationState = child;
1014                break;
1015            }
1016        }
1017
1018        IMemento propertiesState = memento.getChild(IWorkbenchConstants.TAG_PROPERTIES);
1019        if (propertiesState != null) {
1020            IMemento[] props = propertiesState.getChildren(IWorkbenchConstants.TAG_PROPERTY);
1021            for (int i = 0; i < props.length; i++) {
1022                properties.put(props[i].getID(), props[i].getTextData());
1023            }
1024        }
1025                
1026        
1027        return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
1028
}
1029
1030    /* (non-Javadoc)
1031     * @see org.eclipse.ui.internal.LayoutPart#setVisible(boolean)
1032     */

1033    public void setVisible(boolean makeVisible) {
1034        Control ctrl = getControl();
1035        
1036        boolean useShortcut = makeVisible || !isActive;
1037        
1038        if (!SwtUtil.isDisposed(ctrl) && useShortcut) {
1039            if (makeVisible == ctrl.getVisible()) {
1040                return;
1041            }
1042        }
1043        
1044        if (makeVisible) {
1045            for (Iterator JavaDoc iterator = presentableParts.iterator(); iterator.hasNext();) {
1046                PresentablePart next = (PresentablePart) iterator.next();
1047                
1048                next.enableInputs(isActive);
1049                next.enableOutputs(isActive);
1050            }
1051        }
1052        
1053        super.setVisible(makeVisible);
1054        
1055        StackPresentation presentation = getPresentation();
1056        
1057        if (presentation != null) {
1058            presentation.setVisible(makeVisible);
1059        }
1060        
1061        if (!makeVisible) {
1062            for (Iterator JavaDoc iterator = presentableParts.iterator(); iterator.hasNext();) {
1063                PresentablePart next = (PresentablePart) iterator.next();
1064                
1065                next.enableInputs(false);
1066            }
1067        }
1068    }
1069    
1070    /**
1071     * @see IPersistable
1072     */

1073    public IStatus saveState(IMemento memento) {
1074
1075        // Save the active tab.
1076
if (requestedCurrent != null) {
1077            memento.putString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID, requestedCurrent
1078                    .getCompoundId());
1079        }
1080
1081        // Write out the presentable parts (in order)
1082
Set JavaDoc cachedIds = new HashSet JavaDoc();
1083        Iterator JavaDoc ppIter = getPresentableParts().iterator();
1084        while (ppIter.hasNext()) {
1085            PresentablePart presPart = (PresentablePart) ppIter.next();
1086
1087            IMemento childMem = memento
1088                    .createChild(IWorkbenchConstants.TAG_PAGE);
1089            PartPane part = presPart.getPane();
1090            String JavaDoc tabText = part.getPartReference().getPartName();
1091
1092            childMem.putString(IWorkbenchConstants.TAG_LABEL, tabText);
1093            childMem.putString(IWorkbenchConstants.TAG_CONTENT, presPart.getPane().getPlaceHolderId());
1094            
1095            // Cache the id so we don't write it out later
1096
cachedIds.add(presPart.getPane().getPlaceHolderId());
1097        }
1098
1099        Iterator JavaDoc iter = children.iterator();
1100        while (iter.hasNext()) {
1101            LayoutPart next = (LayoutPart) iter.next();
1102
1103            PartPane part = null;
1104            if (next instanceof PartPane) {
1105                // Have we already written it out?
1106
if (cachedIds.contains(((PartPane)next).getPlaceHolderId()))
1107                    continue;
1108                
1109                part = (PartPane)next;
1110            }
1111
1112            IMemento childMem = memento
1113                    .createChild(IWorkbenchConstants.TAG_PAGE);
1114
1115            String JavaDoc tabText = "LabelNotFound"; //$NON-NLS-1$
1116
if (part != null) {
1117                tabText = part.getPartReference().getPartName();
1118            }
1119            childMem.putString(IWorkbenchConstants.TAG_LABEL, tabText);
1120            childMem.putString(IWorkbenchConstants.TAG_CONTENT, next
1121                    .getCompoundId());
1122        }
1123
1124        IPreferenceStore preferenceStore = PrefUtil.getAPIPreferenceStore();
1125        boolean useNewMinMax = preferenceStore.getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
1126        if (useNewMinMax) {
1127            memento.putInteger(IWorkbenchConstants.TAG_EXPANDED, presentationSite.getState());
1128        }
1129        else {
1130            memento
1131            .putInteger(
1132                    IWorkbenchConstants.TAG_EXPANDED,
1133                    (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_MINIMIZED
1134                            : IStackPresentationSite.STATE_RESTORED);
1135        }
1136
1137        memento.putInteger(IWorkbenchConstants.TAG_APPEARANCE, appearance);
1138
1139        savePresentationState();
1140
1141        if (savedPresentationState != null) {
1142            IMemento presentationState = memento
1143                    .createChild(IWorkbenchConstants.TAG_PRESENTATION);
1144            presentationState.putMemento(savedPresentationState);
1145        }
1146        
1147        if (!properties.isEmpty()) {
1148            IMemento propertiesState = memento.createChild(IWorkbenchConstants.TAG_PROPERTIES);
1149            Set JavaDoc ids = properties.keySet();
1150            for (Iterator JavaDoc iterator = ids.iterator(); iterator.hasNext();) {
1151                String JavaDoc id = (String JavaDoc)iterator.next();
1152                
1153                if (properties.get(id) == null) continue;
1154                
1155                IMemento prop = propertiesState.createChild(IWorkbenchConstants.TAG_PROPERTY, id);
1156                prop.putTextData((String JavaDoc)properties.get(id));
1157            }
1158        }
1159        
1160
1161        return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
1162
}
1163
1164    protected WorkbenchPage getPage() {
1165        WorkbenchWindow window = (WorkbenchWindow) getWorkbenchWindow();
1166
1167        if (window == null) {
1168            return null;
1169        }
1170
1171        return (WorkbenchPage) window.getActivePage();
1172    }
1173
1174    /**
1175     * Set the active appearence on the tab folder.
1176     *
1177     * @param active
1178     */

1179    public void setActive(int activeState) {
1180
1181        if (activeState == StackPresentation.AS_ACTIVE_FOCUS && isMinimized) {
1182            setMinimized(false);
1183        }
1184
1185        presentationSite.setActive(activeState);
1186    }
1187
1188    public int getActive() {
1189        return presentationSite.getActive();
1190    }
1191
1192    /**
1193     * Sets the presentation bounds.
1194     */

1195    public void setBounds(Rectangle r) {
1196        
1197        if (getPresentation() != null) {
1198            getPresentation().setBounds(r);
1199        }
1200    }
1201
1202    public void setSelection(LayoutPart part) {
1203        if (part == requestedCurrent) {
1204            return;
1205        }
1206
1207        requestedCurrent = part;
1208        
1209        refreshPresentationSelection();
1210    }
1211
1212    /**
1213     * Subclasses should override this method to update the enablement state of their
1214     * actions
1215     */

1216    protected abstract void updateActions(PresentablePart current);
1217
1218    /* (non-Javadoc)
1219     * @see org.eclipse.ui.internal.LayoutPart#handleDeferredEvents()
1220     */

1221    protected void handleDeferredEvents() {
1222        super.handleDeferredEvents();
1223        
1224        refreshPresentationSelection();
1225    }
1226    
1227    private void refreshPresentationSelection() {
1228        // If deferring UI updates, exit.
1229
if (isDeferred()) {
1230            return;
1231        }
1232        
1233        // If the presentation is already displaying the desired part, then there's nothing
1234
// to do.
1235
if (current == requestedCurrent) {
1236            return;
1237        }
1238
1239        StackPresentation presentation = getPresentation();
1240        if (presentation != null) {
1241        
1242            presentationCurrent = getPresentablePart(requestedCurrent);
1243            
1244            if (!isDisposed()) {
1245                updateActions(presentationCurrent);
1246            }
1247            
1248            if (presentationCurrent != null && presentation != null) {
1249                requestedCurrent.createControl(getParent());
1250                if (requestedCurrent.getControl().getParent() != getControl()
1251                        .getParent()) {
1252                    requestedCurrent.reparent(getControl().getParent());
1253                }
1254
1255               
1256                presentation.selectPart(presentationCurrent);
1257                
1258             }
1259        
1260            // Update the return value of getVisiblePart
1261
current = requestedCurrent;
1262            fireInternalPropertyChange(PROP_SELECTION);
1263        }
1264    }
1265
1266    public int getState() {
1267        return presentationSite.getState();
1268    }
1269
1270    /**
1271     * Sets the minimized state for this stack. The part may call this method to
1272     * minimize or restore itself. The minimized state only affects the view
1273     * when unzoomed in the 3.0 presentation (in 3.3 it's handled by the
1274     * ViewStack directly and works as expected).
1275     */

1276    public void setMinimized(boolean minimized) {
1277        if (minimized != isMinimized) {
1278            isMinimized = minimized;
1279
1280            refreshPresentationState();
1281        }
1282    }
1283    
1284    /* (non-Javadoc)
1285     * @see org.eclipse.ui.internal.ILayoutContainer#obscuredByZoom(org.eclipse.ui.internal.LayoutPart)
1286     */

1287    public boolean childObscuredByZoom(LayoutPart toTest) {
1288        return isObscuredByZoom();
1289    }
1290    
1291    /* (non-Javadoc)
1292     * @see org.eclipse.ui.internal.LayoutPart#requestZoom(org.eclipse.ui.internal.LayoutPart)
1293     */

1294    public void childRequestZoomIn(LayoutPart toZoom) {
1295        super.childRequestZoomIn(toZoom);
1296        
1297        requestZoomIn();
1298    }
1299    /* (non-Javadoc)
1300     * @see org.eclipse.ui.internal.LayoutPart#requestZoomOut()
1301     */

1302    public void childRequestZoomOut() {
1303        super.childRequestZoomOut();
1304        
1305        requestZoomOut();
1306    }
1307
1308    /* (non-Javadoc)
1309     * @see org.eclipse.ui.internal.ILayoutContainer#isZoomed(org.eclipse.ui.internal.LayoutPart)
1310     */

1311    public boolean childIsZoomed(LayoutPart toTest) {
1312        return isZoomed();
1313    }
1314    
1315    /**
1316     * This is a hack that allows us to preserve the old
1317     * min/max behavior for the stack containing the IntroPart.
1318     * This is required to have the initial Intro (Welcome)
1319     * pane to show correctly but will induce strange
1320     * effects should a user re-locate the part to
1321     * stacks other that its initial one...
1322     *
1323     * @return true if the stack contains the intro
1324     * as a ViewPane (not if it's only a placeholder)
1325     */

1326    private boolean isIntroInStack() {
1327        LayoutPart[] kids = getChildren();
1328        for (int i = 0; i < kids.length; i++) {
1329            if (kids[i] instanceof ViewPane) {
1330                ViewPane vp = (ViewPane) kids[i];
1331                if (vp.getID().equals(IIntroConstants.INTRO_VIEW_ID))
1332                    return true;
1333            }
1334        }
1335        return false;
1336    }
1337
1338    private void smartZoom() {
1339        WorkbenchWindow wbw = (WorkbenchWindow) getPage().getWorkbenchWindow();
1340        if (wbw == null || wbw.getShell() == null)
1341            return;
1342
1343        Perspective perspective = getPage().getActivePerspective();
1344        FastViewManager fvm = perspective.getFastViewManager();
1345
1346        fvm.deferUpdates(true);
1347
1348        // Cache the layout bounds
1349
perspective.getPresentation().updateBoundsMap();
1350        
1351        LayoutPart[] children = perspective.getPresentation().getLayout().getChildren();
1352        for (int i = 0; i < children.length; i++) {
1353            if (children[i] != this) {
1354                if (children[i] instanceof ViewStack) {
1355                    ((ViewStack) children[i]).setMinimized(true);
1356                    ViewStackTrimToolBar vstb = fvm
1357                            .getViewStackTrimToolbar(children[i]
1358                                    .getID());
1359                    vstb.setRestoreOnUnzoom(true);
1360                }
1361                else if (children[i] instanceof EditorSashContainer && !(this instanceof EditorStack)) {
1362                    perspective.setEditorAreaState(IStackPresentationSite.STATE_MINIMIZED);
1363                    perspective.setEditorAreaRestoreOnUnzoom(true);
1364                }
1365            }
1366        }
1367
1368        // If the editor area has changed state tell the perspective
1369
if (this instanceof EditorStack)
1370            perspective.setEditorAreaState(IStackPresentationSite.STATE_MAXIMIZED);
1371
1372        // Clear the boundsMap
1373
perspective.getPresentation().resetBoundsMap();
1374        
1375        // We're done batching...
1376
fvm.deferUpdates(false);
1377        
1378        perspective.getPresentation().setMaximizedStack(this);
1379        smartZoomed = true;
1380    }
1381
1382    protected void smartUnzoom() {
1383        // Prevent recursion through 'setMinimized'
1384
if (doingUnzoom)
1385            return;
1386        doingUnzoom = true;
1387        
1388        WorkbenchWindow wbw = (WorkbenchWindow) getPage().getWorkbenchWindow();
1389        if (wbw == null || wbw.getShell() == null)
1390            return;
1391
1392        ITrimManager tbm = wbw.getTrimManager();
1393        Perspective perspective = getPage().getActivePerspective();
1394        FastViewManager fvm = perspective.getFastViewManager();
1395
1396        ILayoutContainer root = getContainer();
1397
1398        // We go up one more level when maximizing an editor stack
1399
// so that we 'zoom' the editor area
1400
boolean restoringEditorArea = false;
1401        if (root instanceof EditorSashContainer) {
1402            root = ((EditorSashContainer) root).getContainer();
1403            restoringEditorArea = true;
1404        }
1405
1406        // This is a compound operation
1407
fvm.deferUpdates(true);
1408        
1409        LayoutPart[] children = root.getChildren();
1410        for (int i = 0; i < children.length; i++) {
1411            if (children[i] != this) {
1412                IWindowTrim trim = tbm.getTrim(children[i].getID());
1413                if (trim == null)
1414                    continue;
1415
1416                if (trim instanceof ViewStackTrimToolBar) {
1417                    ViewStackTrimToolBar vstb = (ViewStackTrimToolBar) trim;
1418                    if (vstb.restoreOnUnzoom()
1419                            && children[i] instanceof ContainerPlaceholder) {
1420                        // In the current presentation its a
1421
// container placeholder
1422
ViewStack realStack = (ViewStack) ((ContainerPlaceholder) children[i])
1423                                .getRealContainer();
1424                        realStack.setMinimized(false);
1425
1426                        vstb.setRestoreOnUnzoom(false);
1427                    }
1428                } else if (trim instanceof EditorAreaTrimToolBar) {
1429                    if (perspective.getEditorAreaRestoreOnUnzoom())
1430                    perspective.setEditorAreaState(IStackPresentationSite.STATE_RESTORED);
1431                }
1432            }
1433        }
1434
1435        // If the editor area has changed state tell the perspective
1436
if (restoringEditorArea)
1437            perspective.setEditorAreaState(IStackPresentationSite.STATE_RESTORED);
1438
1439        perspective.getPresentation().setMaximizedStack(null);
1440        
1441        fvm.deferUpdates(false);
1442        smartZoomed = false;
1443        
1444        doingUnzoom = false;
1445    }
1446    
1447    protected void setState(final int newState) {
1448        final int oldState = presentationSite.getState();
1449        if (!supportsState(newState) || newState == oldState) {
1450            return;
1451        }
1452
1453        final WorkbenchWindow wbw = (WorkbenchWindow) getPage().getWorkbenchWindow();
1454        if (wbw == null || wbw.getShell() == null || wbw.getActiveWorkbenchPage() == null)
1455            return;
1456
1457        WorkbenchPage page = wbw.getActiveWorkbenchPage();
1458        if (page == null)
1459            return;
1460        
1461        boolean useNewMinMax = Perspective.useNewMinMax(page.getActivePerspective());
1462
1463        // we have to fiddle with the zoom behavior to satisfy Intro req's
1464
// by usning the old zoom behavior for its stack
1465
if (newState == IStackPresentationSite.STATE_MAXIMIZED)
1466            useNewMinMax = useNewMinMax && !isIntroInStack();
1467        else if (newState == IStackPresentationSite.STATE_RESTORED) {
1468            PartStack maxStack = page.getActivePerspective().getPresentation().getMaximizedStack();
1469            useNewMinMax = useNewMinMax && maxStack == this;
1470        }
1471
1472        if (useNewMinMax) {
1473            StartupThreading.runWithoutExceptions(new StartupRunnable() {
1474                public void runWithException() throws Throwable JavaDoc {
1475                    wbw.getPageComposite().setRedraw(false);
1476                    try {
1477                        if (newState == IStackPresentationSite.STATE_MAXIMIZED) {
1478                            smartZoom();
1479                        } else if (oldState == IStackPresentationSite.STATE_MAXIMIZED) {
1480                            smartUnzoom();
1481                        }
1482                        
1483                        if (newState == IStackPresentationSite.STATE_MINIMIZED) {
1484                            setMinimized(true);
1485                        }
1486                    } finally {
1487                        wbw.getPageComposite().setRedraw(true);
1488
1489                        // Force a redraw (fixes Mac refresh)
1490
wbw.getShell().redraw();
1491                    }
1492
1493                    setPresentationState(newState);
1494                }
1495            });
1496        } else {
1497            boolean minimized = (newState == IStackPresentationSite.STATE_MINIMIZED);
1498            setMinimized(minimized);
1499
1500            if (newState == IStackPresentationSite.STATE_MAXIMIZED) {
1501                requestZoomIn();
1502            } else if (oldState == IStackPresentationSite.STATE_MAXIMIZED) {
1503                requestZoomOut();
1504                
1505                if (newState == IStackPresentationSite.STATE_MINIMIZED)
1506                    setMinimized(true);
1507            }
1508        }
1509    }
1510    
1511
1512    /**
1513     * Called by the workbench page to notify this part that it has been zoomed or unzoomed.
1514     * The PartStack should not call this method itself -- it must request zoom changes by
1515     * talking to the WorkbenchPage.
1516     */

1517    public void setZoomed(boolean isZoomed) {
1518        
1519        super.setZoomed(isZoomed);
1520        
1521        LayoutPart[] children = getChildren();
1522        
1523        for (int i = 0; i < children.length; i++) {
1524            LayoutPart next = children[i];
1525            
1526            next.setZoomed(isZoomed);
1527        }
1528        
1529        refreshPresentationState();
1530    }
1531    
1532    public boolean isZoomed() {
1533        ILayoutContainer container = getContainer();
1534        
1535        if (container != null) {
1536            return container.childIsZoomed(this);
1537        }
1538        
1539        return false;
1540    }
1541    
1542    protected void refreshPresentationState() {
1543        if (isZoomed() || smartZoomed) {
1544            presentationSite.setPresentationState(IStackPresentationSite.STATE_MAXIMIZED);
1545        } else {
1546            
1547            boolean wasMinimized = (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED);
1548            
1549            if (isMinimized) {
1550                presentationSite.setPresentationState(IStackPresentationSite.STATE_MINIMIZED);
1551            } else {
1552                presentationSite.setPresentationState(IStackPresentationSite.STATE_RESTORED);
1553            }
1554            
1555            if (isMinimized != wasMinimized) {
1556                flushLayout();
1557                
1558                if (isMinimized) {
1559                    WorkbenchPage page = getPage();
1560    
1561                    if (page != null) {
1562                        page.refreshActiveView();
1563                    }
1564                }
1565            }
1566        }
1567    }
1568
1569    /**
1570     * Makes the given part visible in the presentation.
1571     * @param part the part to add to the stack
1572     * @param cookie other information
1573     */

1574    private void showPart(LayoutPart part, Object JavaDoc cookie) {
1575
1576        if (isDisposed()) {
1577            return;
1578        }
1579        
1580        if ((part instanceof PartPlaceholder)) {
1581            part.setContainer(this);
1582            return;
1583        }
1584
1585        if (!(part instanceof PartPane)) {
1586            WorkbenchPlugin.log(NLS.bind(
1587                    WorkbenchMessages.PartStack_incorrectPartInFolder, part
1588                            .getID()));
1589            return;
1590        }
1591        
1592        PartPane pane = (PartPane)part;
1593        
1594        PresentablePart presentablePart = new PresentablePart(pane, getControl().getParent());
1595        presentableParts.add(presentablePart);
1596        
1597        if (isActive) {
1598            part.setContainer(this);
1599        }
1600        
1601        presentationSite.getPresentation().addPart(presentablePart, cookie);
1602
1603        if (requestedCurrent == null) {
1604            setSelection(part);
1605        }
1606        
1607        if (childObscuredByZoom(part)) {
1608            presentablePart.enableInputs(false);
1609        }
1610    }
1611
1612    /**
1613     * Update the container to show the correct visible tab based on the
1614     * activation list.
1615     */

1616    private void updateContainerVisibleTab() {
1617        LayoutPart[] parts = getChildren();
1618
1619        if (parts.length < 1) {
1620            setSelection(null);
1621            return;
1622        }
1623
1624        PartPane selPart = null;
1625        int topIndex = 0;
1626        WorkbenchPage page = getPage();
1627
1628        if (page != null) {
1629            IWorkbenchPartReference sortedPartsArray[] = page.getSortedParts();
1630            List JavaDoc sortedParts = Arrays.asList(sortedPartsArray);
1631            for (int i = 0; i < parts.length; i++) {
1632                if (parts[i] instanceof PartPane) {
1633                    IWorkbenchPartReference part = ((PartPane) parts[i])
1634                            .getPartReference();
1635                    int index = sortedParts.indexOf(part);
1636                    if (index >= topIndex) {
1637                        topIndex = index;
1638                        selPart = (PartPane) parts[i];
1639                    }
1640                }
1641            }
1642
1643        }
1644
1645        if (selPart == null) {
1646            List JavaDoc presentableParts = getPresentableParts();
1647            if (presentableParts.size() != 0) {
1648                IPresentablePart part = (IPresentablePart) getPresentableParts()
1649                        .get(0);
1650
1651                selPart = (PartPane) getPaneFor(part);
1652            }
1653        }
1654
1655        setSelection(selPart);
1656    }
1657
1658    /**
1659     *
1660     */

1661    public void showSystemMenu() {
1662        getPresentation().showSystemMenu();
1663    }
1664
1665    public void showPaneMenu() {
1666        getPresentation().showPaneMenu();
1667    }
1668
1669    public void showPartList() {
1670        getPresentation().showPartList();
1671    }
1672    
1673    public Control[] getTabList(LayoutPart part) {
1674        if (part != null) {
1675            IPresentablePart presentablePart = getPresentablePart(part);
1676            StackPresentation presentation = getPresentation();
1677
1678            if (presentablePart != null && presentation != null) {
1679                return presentation.getTabList(presentablePart);
1680            }
1681        }
1682
1683        return new Control[0];
1684    }
1685
1686    /**
1687     *
1688     * @param beingDragged
1689     * @param initialLocation
1690     * @param keyboard
1691     */

1692    private void dragStart(IPresentablePart beingDragged, Point initialLocation,
1693            boolean keyboard) {
1694        if (beingDragged == null) {
1695            paneDragStart((LayoutPart)null, initialLocation, keyboard);
1696        } else {
1697            if (presentationSite.isPartMoveable(beingDragged)) {
1698                LayoutPart pane = getPaneFor(beingDragged);
1699
1700                if (pane != null) {
1701                    paneDragStart(pane, initialLocation, keyboard);
1702                }
1703            }
1704        }
1705    }
1706    
1707    public void paneDragStart(LayoutPart pane, Point initialLocation,
1708            boolean keyboard) {
1709        if (pane == null) {
1710            if (canMoveFolder()) {
1711                
1712                if (presentationSite.getState() == IStackPresentationSite.STATE_MAXIMIZED) {
1713                    // Calculate where the initial location was BEFORE the 'restore'...as a percentage
1714
Rectangle bounds = Geometry.toDisplay(getParent(), getPresentation().getControl().getBounds());
1715                    float xpct = (initialLocation.x - bounds.x) / (float)(bounds.width);
1716                    float ypct = (initialLocation.y - bounds.y) / (float)(bounds.height);
1717
1718                    setState(IStackPresentationSite.STATE_RESTORED);
1719
1720                    // Now, adjust the initial location to be within the bounds of the restored rect
1721
bounds = Geometry.toDisplay(getParent(), getPresentation().getControl().getBounds());
1722                    initialLocation.x = (int) (bounds.x + (xpct * bounds.width));
1723                    initialLocation.y = (int) (bounds.y + (ypct * bounds.height));
1724                }
1725    
1726                DragUtil.performDrag(PartStack.this, Geometry
1727                        .toDisplay(getParent(), getPresentation().getControl()
1728                                .getBounds()), initialLocation, !keyboard);
1729            }
1730        } else {
1731
1732            if (presentationSite.getState() == IStackPresentationSite.STATE_MAXIMIZED) {
1733                // Calculate where the initial location was BEFORE the 'restore'...as a percentage
1734
Rectangle bounds = Geometry.toDisplay(getParent(), getPresentation().getControl().getBounds());
1735                float xpct = (initialLocation.x - bounds.x) / (float)(bounds.width);
1736                float ypct = (initialLocation.y - bounds.y) / (float)(bounds.height);
1737                
1738                presentationSite.setState(IStackPresentationSite.STATE_RESTORED);
1739
1740                // Now, adjust the initial location to be within the bounds of the restored rect
1741
// See bug 100908
1742
bounds = Geometry.toDisplay(getParent(), getPresentation().getControl().getBounds());
1743                initialLocation.x = (int) (bounds.x + (xpct * bounds.width));
1744                initialLocation.y = (int) (bounds.y + (ypct * bounds.height));
1745            }
1746    
1747            DragUtil.performDrag(pane, Geometry.toDisplay(getParent(),
1748                    getPresentation().getControl().getBounds()),
1749                    initialLocation, !keyboard);
1750        }
1751    }
1752
1753    /**
1754     * @return Returns the savedPresentationState.
1755     */

1756    public IMemento getSavedPresentationState() {
1757        return savedPresentationState;
1758    }
1759    
1760    private void fireInternalPropertyChange(int id) {
1761        Object JavaDoc listeners[] = this.listeners.getListeners();
1762        for (int i = 0; i < listeners.length; i++) {
1763            ((IPropertyListener) listeners[i]).propertyChanged(this, id);
1764        }
1765    }
1766    
1767    // TrimStack Support
1768

1769    /**
1770     * Explicitly sets the presentation state. This is used by the
1771     * new min/max code to force the CTabFolder to show the proper
1772     * state without going through the 'setState' code (which causes
1773     * nasty side-effects.
1774     * @param newState The state to set the presentation to
1775     */

1776    public void setPresentationState(int newState) {
1777        presentationSite.setPresentationState(newState);
1778    }
1779
1780    //
1781
// Support for passing perspective layout properties to the presentation
1782

1783    
1784    public String JavaDoc getProperty(String JavaDoc id) {
1785        return (String JavaDoc)properties.get(id);
1786    }
1787    
1788    public void setProperty(String JavaDoc id, String JavaDoc value) {
1789        if (value==null) {
1790            properties.remove(id);
1791        } else {
1792            properties.put(id, value);
1793        }
1794    }
1795    
1796    /**
1797     * Copies all appearance related data from this stack to the given stack.
1798     */

1799    public void copyAppearanceProperties(PartStack copyTo) {
1800        copyTo.appearance = this.appearance;
1801        if (!properties.isEmpty()) {
1802            Set JavaDoc ids = properties.keySet();
1803            for (Iterator JavaDoc iterator = ids.iterator(); iterator.hasNext();) {
1804                String JavaDoc id = (String JavaDoc)iterator.next();
1805                copyTo.setProperty(id, (String JavaDoc)properties.get(id));
1806            }
1807        }
1808    }
1809}
1810
Popular Tags