0001: /*******************************************************************************
0002: * Copyright (c) 2004, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: * Chris Gross chris.gross@us.ibm.com Bug 107443
0011: *******************************************************************************/package org.eclipse.ui.internal;
0012:
0013: import java.util.ArrayList;
0014: import java.util.Arrays;
0015: import java.util.HashMap;
0016: import java.util.HashSet;
0017: import java.util.Iterator;
0018: import java.util.List;
0019: import java.util.Map;
0020: import java.util.Set;
0021:
0022: import org.eclipse.core.runtime.Assert;
0023: import org.eclipse.core.runtime.IStatus;
0024: import org.eclipse.core.runtime.ListenerList;
0025: import org.eclipse.core.runtime.Status;
0026: import org.eclipse.jface.action.ContributionItem;
0027: import org.eclipse.jface.action.IMenuManager;
0028: import org.eclipse.jface.preference.IPreferenceStore;
0029: import org.eclipse.jface.util.Geometry;
0030: import org.eclipse.osgi.util.NLS;
0031: import org.eclipse.swt.graphics.Cursor;
0032: import org.eclipse.swt.graphics.Point;
0033: import org.eclipse.swt.graphics.Rectangle;
0034: import org.eclipse.swt.widgets.Composite;
0035: import org.eclipse.swt.widgets.Control;
0036: import org.eclipse.swt.widgets.Display;
0037: import org.eclipse.ui.IEditorInput;
0038: import org.eclipse.ui.IMemento;
0039: import org.eclipse.ui.IPersistable;
0040: import org.eclipse.ui.IPropertyListener;
0041: import org.eclipse.ui.IWorkbenchPartReference;
0042: import org.eclipse.ui.IWorkbenchPreferenceConstants;
0043: import org.eclipse.ui.PartInitException;
0044: import org.eclipse.ui.PlatformUI;
0045: import org.eclipse.ui.XMLMemento;
0046: import org.eclipse.ui.internal.StartupThreading.StartupRunnable;
0047: import org.eclipse.ui.internal.dnd.AbstractDropTarget;
0048: import org.eclipse.ui.internal.dnd.DragUtil;
0049: import org.eclipse.ui.internal.dnd.IDropTarget;
0050: import org.eclipse.ui.internal.dnd.SwtUtil;
0051: import org.eclipse.ui.internal.intro.IIntroConstants;
0052: import org.eclipse.ui.internal.layout.ITrimManager;
0053: import org.eclipse.ui.internal.layout.IWindowTrim;
0054: import org.eclipse.ui.internal.presentations.PresentablePart;
0055: import org.eclipse.ui.internal.presentations.PresentationFactoryUtil;
0056: import org.eclipse.ui.internal.presentations.PresentationSerializer;
0057: import org.eclipse.ui.internal.util.PrefUtil;
0058: import org.eclipse.ui.internal.util.Util;
0059: import org.eclipse.ui.presentations.AbstractPresentationFactory;
0060: import org.eclipse.ui.presentations.IPresentablePart;
0061: import org.eclipse.ui.presentations.IStackPresentationSite;
0062: import org.eclipse.ui.presentations.StackDropResult;
0063: import org.eclipse.ui.presentations.StackPresentation;
0064:
0065: /**
0066: * Implements the common behavior for stacks of Panes (ie: EditorStack and ViewStack)
0067: * This layout container has PartPanes as children and belongs to a PartSashContainer.
0068: *
0069: * @since 3.0
0070: */
0071: public abstract class PartStack extends LayoutPart implements
0072: ILayoutContainer {
0073:
0074: public static final int PROP_SELECTION = 0x42;
0075:
0076: private List children = new ArrayList(3);
0077: private boolean isActive = true;
0078: private ArrayList presentableParts = new ArrayList();
0079:
0080: private Map properties = new HashMap();
0081:
0082: protected int appearance = PresentationFactoryUtil.ROLE_VIEW;
0083:
0084: /**
0085: * Stores the last value passed to setSelection. If UI updates are being deferred,
0086: * this may be significantly different from the other current pointers. Once UI updates
0087: * are re-enabled, the stack will update the presentation selection to match the requested
0088: * current pointer.
0089: */
0090: private LayoutPart requestedCurrent;
0091:
0092: /**
0093: * Stores the current part for the stack. Whenever the outside world asks a PartStack
0094: * for the current part, this is what gets returned. This pointer is only updated after
0095: * the presentation selection has been restored and the stack has finished updating its
0096: * internal state. If the stack is still in the process of updating the presentation,
0097: * it will still point to the previous part until the presentation is up-to-date.
0098: */
0099: private LayoutPart current;
0100:
0101: /**
0102: * Stores the presentable part sent to the presentation. Whenever the presentation
0103: * asks for the current part, this is what gets returned. This is updated before sending
0104: * the part to the presentation, and it is not updated while UI updates are disabled.
0105: * When UI updates are enabled, the stack first makes presentationCurrent match
0106: * requestedCurrent. Once the presentation is displaying the correct part, the "current"
0107: * pointer on PartStack is updated.
0108: */
0109: private PresentablePart presentationCurrent;
0110:
0111: private boolean ignoreSelectionChanges = false;
0112:
0113: protected IMemento savedPresentationState = null;
0114:
0115: protected DefaultStackPresentationSite presentationSite = new DefaultStackPresentationSite() {
0116:
0117: public void close(IPresentablePart part) {
0118: PartStack.this .close(part);
0119: }
0120:
0121: public void close(IPresentablePart[] parts) {
0122: PartStack.this .close(parts);
0123: }
0124:
0125: public void dragStart(IPresentablePart beingDragged,
0126: Point initialLocation, boolean keyboard) {
0127: PartStack.this .dragStart(beingDragged, initialLocation,
0128: keyboard);
0129: }
0130:
0131: public void dragStart(Point initialLocation, boolean keyboard) {
0132: PartStack.this .dragStart(null, initialLocation, keyboard);
0133: }
0134:
0135: public boolean isPartMoveable(IPresentablePart part) {
0136: return PartStack.this .isMoveable(part);
0137: }
0138:
0139: public void selectPart(IPresentablePart toSelect) {
0140: PartStack.this .presentationSelectionChanged(toSelect);
0141: }
0142:
0143: public boolean supportsState(int state) {
0144: return PartStack.this .supportsState(state);
0145: }
0146:
0147: public void setState(int newState) {
0148: PartStack.this .setState(newState);
0149: }
0150:
0151: public IPresentablePart getSelectedPart() {
0152: return PartStack.this .getSelectedPart();
0153: }
0154:
0155: public void addSystemActions(IMenuManager menuManager) {
0156: PartStack.this .addSystemActions(menuManager);
0157: }
0158:
0159: public boolean isStackMoveable() {
0160: return canMoveFolder();
0161: }
0162:
0163: public void flushLayout() {
0164: PartStack.this .flushLayout();
0165: }
0166:
0167: public IPresentablePart[] getPartList() {
0168: List parts = getPresentableParts();
0169:
0170: return (IPresentablePart[]) parts
0171: .toArray(new IPresentablePart[parts.size()]);
0172: }
0173:
0174: public String getProperty(String id) {
0175: return PartStack.this .getProperty(id);
0176: }
0177: };
0178:
0179: private static final class PartStackDropResult extends
0180: AbstractDropTarget {
0181: private PartPane pane;
0182:
0183: // Result of the presentation's dragOver method or null if we are stacking over the
0184: // client area of the pane.
0185: private StackDropResult dropResult;
0186: private PartStack stack;
0187:
0188: /**
0189: * Resets the target of this drop result (allows the same drop result object to be
0190: * reused)
0191: *
0192: * @param stack
0193: * @param pane
0194: * @param result result of the presentation's dragOver method, or null if we are
0195: * simply stacking anywhere.
0196: * @since 3.1
0197: */
0198: public void setTarget(PartStack stack, PartPane pane,
0199: StackDropResult result) {
0200: this .pane = pane;
0201: this .dropResult = result;
0202: this .stack = stack;
0203: }
0204:
0205: public void drop() {
0206: // If we're dragging a pane over itself do nothing
0207: //if (dropResult.getInsertionPoint() == pane.getPresentablePart()) { return; };
0208:
0209: Object cookie = null;
0210: if (dropResult != null) {
0211: cookie = dropResult.getCookie();
0212: }
0213:
0214: // Handle cross window drops by opening a new editor
0215: if (pane instanceof EditorPane) {
0216: if (pane.getWorkbenchWindow() != stack
0217: .getWorkbenchWindow()) {
0218: EditorPane editor = (EditorPane) pane;
0219: try {
0220: IEditorInput input = editor
0221: .getEditorReference().getEditorInput();
0222:
0223: // Close the old editor and capture the actual closed state incase of a 'cancel'
0224: boolean editorClosed = editor.getPage()
0225: .closeEditor(
0226: editor.getEditorReference(),
0227: true);
0228:
0229: // Only open open the new editor if the old one closed
0230: if (editorClosed)
0231: stack.getPage()
0232: .openEditor(
0233: input,
0234: editor.getEditorReference()
0235: .getId());
0236: return;
0237: } catch (PartInitException e) {
0238: e.printStackTrace();
0239: }
0240:
0241: }
0242: }
0243:
0244: if (pane.getContainer() != stack) {
0245: // Moving from another stack
0246: stack.derefPart(pane);
0247: pane.reparent(stack.getParent());
0248: stack.add(pane, cookie);
0249: stack.setSelection(pane);
0250: pane.setFocus();
0251: } else if (cookie != null) {
0252: // Rearranging within this stack
0253: stack.getPresentation().movePart(
0254: stack.getPresentablePart(pane), cookie);
0255: }
0256: }
0257:
0258: public Cursor getCursor() {
0259: return DragCursors.getCursor(DragCursors.CENTER);
0260: }
0261:
0262: public Rectangle getSnapRectangle() {
0263: if (dropResult == null) {
0264: return DragUtil.getDisplayBounds(stack.getControl());
0265: }
0266: return dropResult.getSnapRectangle();
0267: }
0268: }
0269:
0270: private static final PartStackDropResult dropResult = new PartStackDropResult();
0271:
0272: protected boolean isMinimized;
0273:
0274: private ListenerList listeners = new ListenerList();
0275:
0276: /**
0277: * Custom presentation factory to use for this stack, or null to
0278: * use the default
0279: */
0280: private AbstractPresentationFactory factory;
0281:
0282: private boolean smartZoomed = false;
0283: private boolean doingUnzoom = false;
0284:
0285: protected abstract boolean isMoveable(IPresentablePart part);
0286:
0287: protected abstract void addSystemActions(IMenuManager menuManager);
0288:
0289: protected abstract boolean supportsState(int newState);
0290:
0291: protected abstract boolean canMoveFolder();
0292:
0293: protected abstract void derefPart(LayoutPart toDeref);
0294:
0295: protected abstract boolean allowsDrop(PartPane part);
0296:
0297: protected static void appendToGroupIfPossible(IMenuManager m,
0298: String groupId, ContributionItem item) {
0299: try {
0300: m.appendToGroup(groupId, item);
0301: } catch (IllegalArgumentException e) {
0302: m.add(item);
0303: }
0304: }
0305:
0306: /**
0307: * Creates a new PartStack, given a constant determining which presentation to use
0308: *
0309: * @param appearance one of the PresentationFactoryUtil.ROLE_* constants
0310: */
0311: public PartStack(int appearance) {
0312: this (appearance, null);
0313: }
0314:
0315: /**
0316: * Creates a new part stack that uses the given custom presentation factory
0317: * @param appearance
0318: * @param factory custom factory to use (or null to use the default)
0319: */
0320: public PartStack(int appearance, AbstractPresentationFactory factory) {
0321: super ("PartStack"); //$NON-NLS-1$
0322:
0323: this .appearance = appearance;
0324: this .factory = factory;
0325: }
0326:
0327: /**
0328: * Adds a property listener to this stack. The listener will receive a PROP_SELECTION
0329: * event whenever the result of getSelection changes
0330: *
0331: * @param listener
0332: */
0333: public void addListener(IPropertyListener listener) {
0334: listeners.add(listener);
0335: }
0336:
0337: public void removeListener(IPropertyListener listener) {
0338: listeners.remove(listener);
0339: }
0340:
0341: protected final boolean isStandalone() {
0342: return (appearance == PresentationFactoryUtil.ROLE_STANDALONE || appearance == PresentationFactoryUtil.ROLE_STANDALONE_NOTITLE);
0343: }
0344:
0345: /**
0346: * Returns the currently selected IPresentablePart, or null if none
0347: *
0348: * @return
0349: */
0350: protected IPresentablePart getSelectedPart() {
0351: return presentationCurrent;
0352: }
0353:
0354: protected IStackPresentationSite getPresentationSite() {
0355: return presentationSite;
0356: }
0357:
0358: /**
0359: * Tests the integrity of this object. Throws an exception if the object's state
0360: * is invalid. For use in test suites.
0361: */
0362: public void testInvariants() {
0363: Control focusControl = Display.getCurrent().getFocusControl();
0364:
0365: boolean currentFound = false;
0366:
0367: LayoutPart[] children = getChildren();
0368:
0369: for (int idx = 0; idx < children.length; idx++) {
0370: LayoutPart child = children[idx];
0371:
0372: // No null children allowed
0373: Assert.isNotNull(child,
0374: "null children are not allowed in PartStack"); //$NON-NLS-1$
0375:
0376: // This object can only contain placeholders or PartPanes
0377: Assert
0378: .isTrue(child instanceof PartPlaceholder
0379: || child instanceof PartPane,
0380: "PartStack can only contain PartPlaceholders or PartPanes"); //$NON-NLS-1$
0381:
0382: // Ensure that all the PartPanes have an associated presentable part
0383: IPresentablePart part = getPresentablePart(child);
0384: if (child instanceof PartPane) {
0385: Assert
0386: .isNotNull(part,
0387: "All PartPanes must have a non-null IPresentablePart"); //$NON-NLS-1$
0388: }
0389:
0390: // Ensure that the child's backpointer points to this stack
0391: ILayoutContainer childContainer = child.getContainer();
0392:
0393: // Disable tests for placeholders -- PartPlaceholder backpointers don't
0394: // obey the usual rules -- they sometimes point to a container placeholder
0395: // for this stack instead of the real stack.
0396: if (!(child instanceof PartPlaceholder)) {
0397:
0398: if (isDisposed()) {
0399:
0400: // Currently, we allow null backpointers if the widgetry is disposed.
0401: // However, it is never valid for the child to have a parent other than
0402: // this object
0403: if (childContainer != null) {
0404: Assert
0405: .isTrue(childContainer == this ,
0406: "PartStack has a child that thinks it has a different parent"); //$NON-NLS-1$
0407: }
0408: } else {
0409: // If the widgetry exists, the child's backpointer must point to us
0410: Assert
0411: .isTrue(childContainer == this ,
0412: "PartStack has a child that thinks it has a different parent"); //$NON-NLS-1$
0413:
0414: // If this child has focus, then ensure that it is selected and that we have
0415: // the active appearance.
0416:
0417: if (SwtUtil.isChild(child.getControl(),
0418: focusControl)) {
0419: Assert
0420: .isTrue(child == current,
0421: "The part with focus is not the selected part"); //$NON-NLS-1$
0422: // focus check commented out since it fails when focus workaround in LayoutPart.setVisible is not present
0423: // Assert.isTrue(getActive() == StackPresentation.AS_ACTIVE_FOCUS);
0424: }
0425: }
0426: }
0427:
0428: // Ensure that "current" points to a valid child
0429: if (child == current) {
0430: currentFound = true;
0431: }
0432:
0433: // Test the child's internal state
0434: child.testInvariants();
0435: }
0436:
0437: // If we have at least one child, ensure that the "current" pointer points to one of them
0438: if (!isDisposed() && getPresentableParts().size() > 0) {
0439: Assert.isTrue(currentFound);
0440:
0441: if (!isDisposed()) {
0442: StackPresentation presentation = getPresentation();
0443:
0444: // If the presentation controls have focus, ensure that we have the active appearance
0445: if (SwtUtil.isChild(presentation.getControl(),
0446: focusControl)) {
0447: Assert
0448: .isTrue(
0449: getActive() == StackPresentation.AS_ACTIVE_FOCUS,
0450: "The presentation has focus but does not have the active appearance"); //$NON-NLS-1$
0451: }
0452: }
0453: }
0454:
0455: // Check to that we're displaying the zoomed icon iff we're actually maximized
0456: Assert
0457: .isTrue((getState() == IStackPresentationSite.STATE_MAXIMIZED) == (getContainer() != null && getContainer()
0458: .childIsZoomed(this )));
0459:
0460: }
0461:
0462: /* (non-Javadoc)
0463: * @see org.eclipse.ui.internal.LayoutPart#describeLayout(java.lang.StringBuffer)
0464: */
0465: public void describeLayout(StringBuffer buf) {
0466: int activeState = getActive();
0467: if (activeState == StackPresentation.AS_ACTIVE_FOCUS) {
0468: buf.append("active "); //$NON-NLS-1$
0469: } else if (activeState == StackPresentation.AS_ACTIVE_NOFOCUS) {
0470: buf.append("active_nofocus "); //$NON-NLS-1$
0471: }
0472:
0473: buf.append("("); //$NON-NLS-1$
0474:
0475: LayoutPart[] children = ((ILayoutContainer) this ).getChildren();
0476:
0477: int visibleChildren = 0;
0478:
0479: for (int idx = 0; idx < children.length; idx++) {
0480:
0481: LayoutPart next = children[idx];
0482: if (!(next instanceof PartPlaceholder)) {
0483: if (idx > 0) {
0484: buf.append(", "); //$NON-NLS-1$
0485: }
0486:
0487: if (next == requestedCurrent) {
0488: buf.append("*"); //$NON-NLS-1$
0489: }
0490:
0491: next.describeLayout(buf);
0492:
0493: visibleChildren++;
0494: }
0495: }
0496:
0497: buf.append(")"); //$NON-NLS-1$
0498: }
0499:
0500: /**
0501: * See IVisualContainer#add
0502: */
0503: public void add(LayoutPart child) {
0504: add(child, null);
0505: }
0506:
0507: /**
0508: * Add a part at a particular position
0509: */
0510: protected void add(LayoutPart newChild, Object cookie) {
0511: children.add(newChild);
0512:
0513: // Fix for bug 78470:
0514: if (!(newChild.getContainer() instanceof ContainerPlaceholder)) {
0515: newChild.setContainer(this );
0516: }
0517:
0518: showPart(newChild, cookie);
0519: }
0520:
0521: public boolean allowsAdd(LayoutPart toAdd) {
0522: return !isStandalone();
0523: }
0524:
0525: /*
0526: * (non-Javadoc)
0527: *
0528: * @see org.eclipse.ui.internal.ILayoutContainer#allowsAutoFocus()
0529: */
0530: public boolean allowsAutoFocus() {
0531: if (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED) {
0532: return false;
0533: }
0534:
0535: return super .allowsAutoFocus();
0536: }
0537:
0538: /**
0539: * @param parts
0540: */
0541: protected void close(IPresentablePart[] parts) {
0542: for (int idx = 0; idx < parts.length; idx++) {
0543: IPresentablePart part = parts[idx];
0544:
0545: close(part);
0546: }
0547: }
0548:
0549: /**
0550: * @param part
0551: */
0552: protected void close(IPresentablePart part) {
0553: if (!presentationSite.isCloseable(part)) {
0554: return;
0555: }
0556:
0557: LayoutPart layoutPart = getPaneFor(part);
0558:
0559: if (layoutPart != null && layoutPart instanceof PartPane) {
0560: PartPane viewPane = (PartPane) layoutPart;
0561:
0562: viewPane.doHide();
0563: }
0564: }
0565:
0566: public boolean isDisposed() {
0567: return getPresentation() == null;
0568: }
0569:
0570: protected AbstractPresentationFactory getFactory() {
0571:
0572: if (factory != null) {
0573: return factory;
0574: }
0575:
0576: return ((WorkbenchWindow) getPage().getWorkbenchWindow())
0577: .getWindowConfigurer().getPresentationFactory();
0578: }
0579:
0580: public void createControl(Composite parent) {
0581: if (!isDisposed()) {
0582: return;
0583: }
0584:
0585: AbstractPresentationFactory factory = getFactory();
0586:
0587: PresentationSerializer serializer = new PresentationSerializer(
0588: getPresentableParts());
0589:
0590: StackPresentation presentation = PresentationFactoryUtil
0591: .createPresentation(factory, appearance, parent,
0592: presentationSite, serializer,
0593: savedPresentationState);
0594:
0595: createControl(parent, presentation);
0596: getControl().moveBelow(null);
0597: }
0598:
0599: /* (non-Javadoc)
0600: * @see org.eclipse.ui.internal.LayoutPart#getDropTarget(java.lang.Object, org.eclipse.swt.graphics.Point)
0601: */
0602: public IDropTarget getDropTarget(Object draggedObject,
0603: Point position) {
0604:
0605: if (!(draggedObject instanceof PartPane)) {
0606: return null;
0607: }
0608:
0609: final PartPane pane = (PartPane) draggedObject;
0610: if (isStandalone() || !allowsDrop(pane)) {
0611: return null;
0612: }
0613:
0614: // Don't allow views to be dragged between windows
0615: boolean differentWindows = pane.getWorkbenchWindow() != getWorkbenchWindow();
0616: boolean editorDropOK = ((pane instanceof EditorPane) && pane
0617: .getWorkbenchWindow().getWorkbench() == getWorkbenchWindow()
0618: .getWorkbench());
0619: if (differentWindows && !editorDropOK) {
0620: return null;
0621: }
0622:
0623: StackDropResult dropResult = getPresentation().dragOver(
0624: getControl(), position);
0625:
0626: if (dropResult == null) {
0627: return null;
0628: }
0629:
0630: return createDropTarget(pane, dropResult);
0631: }
0632:
0633: public void setActive(boolean isActive) {
0634:
0635: this .isActive = isActive;
0636: // Add all visible children to the presentation
0637: Iterator iter = children.iterator();
0638: while (iter.hasNext()) {
0639: LayoutPart part = (LayoutPart) iter.next();
0640:
0641: part.setContainer(isActive ? this : null);
0642: }
0643:
0644: for (Iterator iterator = presentableParts.iterator(); iterator
0645: .hasNext();) {
0646: PresentablePart next = (PresentablePart) iterator.next();
0647:
0648: next.enableInputs(isActive);
0649: next.enableOutputs(isActive);
0650: }
0651: }
0652:
0653: public void createControl(Composite parent,
0654: StackPresentation presentation) {
0655:
0656: Assert.isTrue(isDisposed());
0657:
0658: if (presentationSite.getPresentation() != null) {
0659: return;
0660: }
0661:
0662: presentationSite.setPresentation(presentation);
0663:
0664: // Add all visible children to the presentation
0665: // Use a copy of the current set of children to avoid a ConcurrentModificationException
0666: // if a part is added to the same stack while iterating over the children (bug 78470)
0667: LayoutPart[] childParts = (LayoutPart[]) children
0668: .toArray(new LayoutPart[children.size()]);
0669: for (int i = 0; i < childParts.length; i++) {
0670: LayoutPart part = childParts[i];
0671: showPart(part, null);
0672: }
0673:
0674: if (savedPresentationState != null) {
0675: PresentationSerializer serializer = new PresentationSerializer(
0676: getPresentableParts());
0677: presentation.restoreState(serializer,
0678: savedPresentationState);
0679: }
0680:
0681: Control ctrl = getPresentation().getControl();
0682:
0683: ctrl.setData(this );
0684:
0685: // We should not have a placeholder selected once we've created the widgetry
0686: if (requestedCurrent instanceof PartPlaceholder) {
0687: requestedCurrent = null;
0688: updateContainerVisibleTab();
0689: }
0690:
0691: refreshPresentationSelection();
0692: }
0693:
0694: public IDropTarget createDropTarget(PartPane pane,
0695: StackDropResult result) {
0696: dropResult.setTarget(this , pane, result);
0697: return dropResult;
0698: }
0699:
0700: /**
0701: * Saves the current state of the presentation to savedPresentationState, if the
0702: * presentation exists.
0703: */
0704: protected void savePresentationState() {
0705: if (isDisposed()) {
0706: return;
0707: }
0708:
0709: {// Save the presentation's state before disposing it
0710: XMLMemento memento = XMLMemento
0711: .createWriteRoot(IWorkbenchConstants.TAG_PRESENTATION);
0712: memento.putString(IWorkbenchConstants.TAG_ID, getFactory()
0713: .getId());
0714:
0715: PresentationSerializer serializer = new PresentationSerializer(
0716: getPresentableParts());
0717:
0718: getPresentation().saveState(serializer, memento);
0719:
0720: // Store the memento in savedPresentationState
0721: savedPresentationState = memento;
0722: }
0723: }
0724:
0725: /**
0726: * See LayoutPart#dispose
0727: */
0728: public void dispose() {
0729:
0730: if (isDisposed()) {
0731: return;
0732: }
0733:
0734: savePresentationState();
0735:
0736: presentationSite.dispose();
0737:
0738: for (Iterator iter = presentableParts.iterator(); iter
0739: .hasNext();) {
0740: PresentablePart part = (PresentablePart) iter.next();
0741:
0742: part.dispose();
0743: }
0744: presentableParts.clear();
0745:
0746: presentationCurrent = null;
0747: current = null;
0748: fireInternalPropertyChange(PROP_SELECTION);
0749: }
0750:
0751: public void findSashes(LayoutPart part, PartPane.Sashes sashes) {
0752: ILayoutContainer container = getContainer();
0753:
0754: if (container != null) {
0755: container.findSashes(this , sashes);
0756: }
0757: }
0758:
0759: /**
0760: * Gets the presentation bounds.
0761: */
0762: public Rectangle getBounds() {
0763: if (getPresentation() == null) {
0764: return new Rectangle(0, 0, 0, 0);
0765: }
0766:
0767: return getPresentation().getControl().getBounds();
0768: }
0769:
0770: /**
0771: * See IVisualContainer#getChildren
0772: */
0773: public LayoutPart[] getChildren() {
0774: return (LayoutPart[]) children.toArray(new LayoutPart[children
0775: .size()]);
0776: }
0777:
0778: public Control getControl() {
0779: StackPresentation presentation = getPresentation();
0780:
0781: if (presentation == null) {
0782: return null;
0783: }
0784:
0785: return presentation.getControl();
0786: }
0787:
0788: /**
0789: * Answer the number of children.
0790: */
0791: public int getItemCount() {
0792: if (isDisposed()) {
0793: return children.size();
0794: }
0795: return getPresentableParts().size();
0796: }
0797:
0798: /**
0799: * Returns the LayoutPart for the given IPresentablePart, or null if the given
0800: * IPresentablePart is not in this stack. Returns null if given a null argument.
0801: *
0802: * @param part to locate or null
0803: * @return
0804: */
0805: protected LayoutPart getPaneFor(IPresentablePart part) {
0806: if (part == null || !(part instanceof PresentablePart)) {
0807: return null;
0808: }
0809:
0810: return ((PresentablePart) part).getPane();
0811: }
0812:
0813: /**
0814: * Get the parent control.
0815: */
0816: public Composite getParent() {
0817: return getControl().getParent();
0818: }
0819:
0820: /**
0821: * Returns a list of IPresentablePart
0822: *
0823: * @return
0824: */
0825: public List getPresentableParts() {
0826: return presentableParts;
0827: }
0828:
0829: private PresentablePart getPresentablePart(LayoutPart pane) {
0830: for (Iterator iter = presentableParts.iterator(); iter
0831: .hasNext();) {
0832: PresentablePart part = (PresentablePart) iter.next();
0833:
0834: if (part.getPane() == pane) {
0835: return part;
0836: }
0837: }
0838:
0839: return null;
0840: }
0841:
0842: protected StackPresentation getPresentation() {
0843: return presentationSite.getPresentation();
0844: }
0845:
0846: /**
0847: * Returns the visible child.
0848: * @return the currently visible part, or null if none
0849: */
0850: public PartPane getSelection() {
0851: if (current instanceof PartPane) {
0852: return (PartPane) current;
0853: }
0854: return null;
0855: }
0856:
0857: private void presentationSelectionChanged(
0858: IPresentablePart newSelection) {
0859: // Ignore selection changes that occur as a result of removing a part
0860: if (ignoreSelectionChanges) {
0861: return;
0862: }
0863: LayoutPart newPart = getPaneFor(newSelection);
0864:
0865: // This method should only be called on objects that are already in the layout
0866: Assert.isNotNull(newPart);
0867:
0868: if (newPart == requestedCurrent) {
0869: return;
0870: }
0871:
0872: setSelection(newPart);
0873:
0874: if (newPart != null) {
0875: newPart.setFocus();
0876: }
0877:
0878: }
0879:
0880: /**
0881: * See IVisualContainer#remove
0882: */
0883: public void remove(LayoutPart child) {
0884: PresentablePart presentablePart = getPresentablePart(child);
0885:
0886: // Need to remove it from the list of children before notifying the presentation
0887: // since it may setVisible(false) on the part, leading to a partHidden notification,
0888: // during which findView must not find the view being removed. See bug 60039.
0889: children.remove(child);
0890:
0891: StackPresentation presentation = getPresentation();
0892:
0893: if (presentablePart != null && presentation != null) {
0894: ignoreSelectionChanges = true;
0895: presentableParts.remove(presentablePart);
0896: presentation.removePart(presentablePart);
0897: presentablePart.dispose();
0898: ignoreSelectionChanges = false;
0899: }
0900:
0901: if (!isDisposed()) {
0902: child.setContainer(null);
0903: }
0904:
0905: if (child == requestedCurrent) {
0906: updateContainerVisibleTab();
0907: }
0908: }
0909:
0910: /**
0911: * Reparent a part. Also reparent visible children...
0912: */
0913: public void reparent(Composite newParent) {
0914:
0915: Control control = getControl();
0916: if ((control == null) || (control.getParent() == newParent)
0917: || !control.isReparentable()) {
0918: return;
0919: }
0920:
0921: super .reparent(newParent);
0922:
0923: Iterator iter = children.iterator();
0924: while (iter.hasNext()) {
0925: LayoutPart next = (LayoutPart) iter.next();
0926: next.reparent(newParent);
0927: }
0928: }
0929:
0930: /**
0931: * See IVisualContainer#replace
0932: */
0933: public void replace(LayoutPart oldChild, LayoutPart newChild) {
0934: int idx = children.indexOf(oldChild);
0935: int numPlaceholders = 0;
0936: //subtract the number of placeholders still existing in the list
0937: //before this one - they wont have parts.
0938: for (int i = 0; i < idx; i++) {
0939: if (children.get(i) instanceof PartPlaceholder) {
0940: numPlaceholders++;
0941: }
0942: }
0943: Integer cookie = new Integer(idx - numPlaceholders);
0944: children.add(idx, newChild);
0945:
0946: showPart(newChild, cookie);
0947:
0948: if (oldChild == requestedCurrent
0949: && !(newChild instanceof PartPlaceholder)) {
0950: setSelection(newChild);
0951: }
0952:
0953: remove(oldChild);
0954: }
0955:
0956: /* (non-Javadoc)
0957: * @see org.eclipse.ui.internal.LayoutPart#computePreferredSize(boolean, int, int, int)
0958: */
0959: public int computePreferredSize(boolean width,
0960: int availableParallel, int availablePerpendicular,
0961: int preferredParallel) {
0962:
0963: return getPresentation().computePreferredSize(width,
0964: availableParallel, availablePerpendicular,
0965: preferredParallel);
0966: }
0967:
0968: /* (non-Javadoc)
0969: * @see org.eclipse.ui.internal.LayoutPart#getSizeFlags(boolean)
0970: */
0971: public int getSizeFlags(boolean horizontal) {
0972: StackPresentation presentation = getPresentation();
0973:
0974: if (presentation != null) {
0975: return presentation.getSizeFlags(horizontal);
0976: }
0977:
0978: return 0;
0979: }
0980:
0981: /**
0982: * @see IPersistable
0983: */
0984: public IStatus restoreState(IMemento memento) {
0985: // Read the active tab.
0986: String activeTabID = memento
0987: .getString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID);
0988:
0989: // Read the page elements.
0990: IMemento[] children = memento
0991: .getChildren(IWorkbenchConstants.TAG_PAGE);
0992: if (children != null) {
0993: // Loop through the page elements.
0994: for (int i = 0; i < children.length; i++) {
0995: // Get the info details.
0996: IMemento childMem = children[i];
0997: String partID = childMem
0998: .getString(IWorkbenchConstants.TAG_CONTENT);
0999:
1000: // Create the part.
1001: LayoutPart part = new PartPlaceholder(partID);
1002: part.setContainer(this );
1003: add(part);
1004: //1FUN70C: ITPUI:WIN - Shouldn't set Container when not active
1005: //part.setContainer(this);
1006: if (partID.equals(activeTabID)) {
1007: setSelection(part);
1008: // Mark this as the active part.
1009: //current = part;
1010: }
1011: }
1012: }
1013:
1014: IPreferenceStore preferenceStore = PrefUtil
1015: .getAPIPreferenceStore();
1016: boolean useNewMinMax = preferenceStore
1017: .getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
1018: final Integer expanded = memento
1019: .getInteger(IWorkbenchConstants.TAG_EXPANDED);
1020: if (useNewMinMax && expanded != null) {
1021: StartupThreading
1022: .runWithoutExceptions(new StartupRunnable() {
1023: public void runWithException() throws Throwable {
1024: setState((expanded == null || expanded
1025: .intValue() != IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_RESTORED
1026: : IStackPresentationSite.STATE_MINIMIZED);
1027: }
1028: });
1029: } else {
1030: setState((expanded == null || expanded.intValue() != IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_RESTORED
1031: : IStackPresentationSite.STATE_MINIMIZED);
1032: }
1033:
1034: Integer appearance = memento
1035: .getInteger(IWorkbenchConstants.TAG_APPEARANCE);
1036: if (appearance != null) {
1037: this .appearance = appearance.intValue();
1038: }
1039:
1040: // Determine if the presentation has saved any info here
1041: savedPresentationState = null;
1042: IMemento[] presentationMementos = memento
1043: .getChildren(IWorkbenchConstants.TAG_PRESENTATION);
1044:
1045: for (int idx = 0; idx < presentationMementos.length; idx++) {
1046: IMemento child = presentationMementos[idx];
1047:
1048: String id = child.getString(IWorkbenchConstants.TAG_ID);
1049:
1050: if (Util.equals(id, getFactory().getId())) {
1051: savedPresentationState = child;
1052: break;
1053: }
1054: }
1055:
1056: IMemento propertiesState = memento
1057: .getChild(IWorkbenchConstants.TAG_PROPERTIES);
1058: if (propertiesState != null) {
1059: IMemento[] props = propertiesState
1060: .getChildren(IWorkbenchConstants.TAG_PROPERTY);
1061: for (int i = 0; i < props.length; i++) {
1062: properties
1063: .put(props[i].getID(), props[i].getTextData());
1064: }
1065: }
1066:
1067: return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
1068: }
1069:
1070: /* (non-Javadoc)
1071: * @see org.eclipse.ui.internal.LayoutPart#setVisible(boolean)
1072: */
1073: public void setVisible(boolean makeVisible) {
1074: Control ctrl = getControl();
1075:
1076: boolean useShortcut = makeVisible || !isActive;
1077:
1078: if (!SwtUtil.isDisposed(ctrl) && useShortcut) {
1079: if (makeVisible == ctrl.getVisible()) {
1080: return;
1081: }
1082: }
1083:
1084: if (makeVisible) {
1085: for (Iterator iterator = presentableParts.iterator(); iterator
1086: .hasNext();) {
1087: PresentablePart next = (PresentablePart) iterator
1088: .next();
1089:
1090: next.enableInputs(isActive);
1091: next.enableOutputs(isActive);
1092: }
1093: }
1094:
1095: super .setVisible(makeVisible);
1096:
1097: StackPresentation presentation = getPresentation();
1098:
1099: if (presentation != null) {
1100: presentation.setVisible(makeVisible);
1101: }
1102:
1103: if (!makeVisible) {
1104: for (Iterator iterator = presentableParts.iterator(); iterator
1105: .hasNext();) {
1106: PresentablePart next = (PresentablePart) iterator
1107: .next();
1108:
1109: next.enableInputs(false);
1110: }
1111: }
1112: }
1113:
1114: /**
1115: * @see IPersistable
1116: */
1117: public IStatus saveState(IMemento memento) {
1118:
1119: // Save the active tab.
1120: if (requestedCurrent != null) {
1121: memento.putString(IWorkbenchConstants.TAG_ACTIVE_PAGE_ID,
1122: requestedCurrent.getCompoundId());
1123: }
1124:
1125: // Write out the presentable parts (in order)
1126: Set cachedIds = new HashSet();
1127: Iterator ppIter = getPresentableParts().iterator();
1128: while (ppIter.hasNext()) {
1129: PresentablePart presPart = (PresentablePart) ppIter.next();
1130:
1131: IMemento childMem = memento
1132: .createChild(IWorkbenchConstants.TAG_PAGE);
1133: PartPane part = presPart.getPane();
1134: String tabText = part.getPartReference().getPartName();
1135:
1136: childMem.putString(IWorkbenchConstants.TAG_LABEL, tabText);
1137: childMem.putString(IWorkbenchConstants.TAG_CONTENT,
1138: presPart.getPane().getPlaceHolderId());
1139:
1140: // Cache the id so we don't write it out later
1141: cachedIds.add(presPart.getPane().getPlaceHolderId());
1142: }
1143:
1144: Iterator iter = children.iterator();
1145: while (iter.hasNext()) {
1146: LayoutPart next = (LayoutPart) iter.next();
1147:
1148: PartPane part = null;
1149: if (next instanceof PartPane) {
1150: // Have we already written it out?
1151: if (cachedIds.contains(((PartPane) next)
1152: .getPlaceHolderId()))
1153: continue;
1154:
1155: part = (PartPane) next;
1156: }
1157:
1158: IMemento childMem = memento
1159: .createChild(IWorkbenchConstants.TAG_PAGE);
1160:
1161: String tabText = "LabelNotFound"; //$NON-NLS-1$
1162: if (part != null) {
1163: tabText = part.getPartReference().getPartName();
1164: }
1165: childMem.putString(IWorkbenchConstants.TAG_LABEL, tabText);
1166: childMem.putString(IWorkbenchConstants.TAG_CONTENT, next
1167: .getCompoundId());
1168: }
1169:
1170: IPreferenceStore preferenceStore = PrefUtil
1171: .getAPIPreferenceStore();
1172: boolean useNewMinMax = preferenceStore
1173: .getBoolean(IWorkbenchPreferenceConstants.ENABLE_NEW_MIN_MAX);
1174: if (useNewMinMax) {
1175: memento.putInteger(IWorkbenchConstants.TAG_EXPANDED,
1176: presentationSite.getState());
1177: } else {
1178: memento
1179: .putInteger(
1180: IWorkbenchConstants.TAG_EXPANDED,
1181: (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED) ? IStackPresentationSite.STATE_MINIMIZED
1182: : IStackPresentationSite.STATE_RESTORED);
1183: }
1184:
1185: memento.putInteger(IWorkbenchConstants.TAG_APPEARANCE,
1186: appearance);
1187:
1188: savePresentationState();
1189:
1190: if (savedPresentationState != null) {
1191: IMemento presentationState = memento
1192: .createChild(IWorkbenchConstants.TAG_PRESENTATION);
1193: presentationState.putMemento(savedPresentationState);
1194: }
1195:
1196: if (!properties.isEmpty()) {
1197: IMemento propertiesState = memento
1198: .createChild(IWorkbenchConstants.TAG_PROPERTIES);
1199: Set ids = properties.keySet();
1200: for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1201: String id = (String) iterator.next();
1202:
1203: if (properties.get(id) == null)
1204: continue;
1205:
1206: IMemento prop = propertiesState.createChild(
1207: IWorkbenchConstants.TAG_PROPERTY, id);
1208: prop.putTextData((String) properties.get(id));
1209: }
1210: }
1211:
1212: return new Status(IStatus.OK, PlatformUI.PLUGIN_ID, 0, "", null); //$NON-NLS-1$
1213: }
1214:
1215: protected WorkbenchPage getPage() {
1216: WorkbenchWindow window = (WorkbenchWindow) getWorkbenchWindow();
1217:
1218: if (window == null) {
1219: return null;
1220: }
1221:
1222: return (WorkbenchPage) window.getActivePage();
1223: }
1224:
1225: /**
1226: * Set the active appearence on the tab folder.
1227: *
1228: * @param active
1229: */
1230: public void setActive(int activeState) {
1231:
1232: if (activeState == StackPresentation.AS_ACTIVE_FOCUS
1233: && isMinimized) {
1234: setMinimized(false);
1235: }
1236:
1237: presentationSite.setActive(activeState);
1238: }
1239:
1240: public int getActive() {
1241: return presentationSite.getActive();
1242: }
1243:
1244: /**
1245: * Sets the presentation bounds.
1246: */
1247: public void setBounds(Rectangle r) {
1248:
1249: if (getPresentation() != null) {
1250: getPresentation().setBounds(r);
1251: }
1252: }
1253:
1254: public void setSelection(LayoutPart part) {
1255: if (part == requestedCurrent) {
1256: return;
1257: }
1258:
1259: requestedCurrent = part;
1260:
1261: refreshPresentationSelection();
1262: }
1263:
1264: /**
1265: * Subclasses should override this method to update the enablement state of their
1266: * actions
1267: */
1268: protected abstract void updateActions(PresentablePart current);
1269:
1270: /* (non-Javadoc)
1271: * @see org.eclipse.ui.internal.LayoutPart#handleDeferredEvents()
1272: */
1273: protected void handleDeferredEvents() {
1274: super .handleDeferredEvents();
1275:
1276: refreshPresentationSelection();
1277: }
1278:
1279: private void refreshPresentationSelection() {
1280: // If deferring UI updates, exit.
1281: if (isDeferred()) {
1282: return;
1283: }
1284:
1285: // If the presentation is already displaying the desired part, then there's nothing
1286: // to do.
1287: if (current == requestedCurrent) {
1288: return;
1289: }
1290:
1291: StackPresentation presentation = getPresentation();
1292: if (presentation != null) {
1293:
1294: presentationCurrent = getPresentablePart(requestedCurrent);
1295:
1296: if (!isDisposed()) {
1297: updateActions(presentationCurrent);
1298: }
1299:
1300: if (presentationCurrent != null && presentation != null) {
1301: requestedCurrent.createControl(getParent());
1302: if (requestedCurrent.getControl().getParent() != getControl()
1303: .getParent()) {
1304: requestedCurrent.reparent(getControl().getParent());
1305: }
1306:
1307: presentation.selectPart(presentationCurrent);
1308:
1309: }
1310:
1311: // Update the return value of getVisiblePart
1312: current = requestedCurrent;
1313: fireInternalPropertyChange(PROP_SELECTION);
1314: }
1315: }
1316:
1317: public int getState() {
1318: return presentationSite.getState();
1319: }
1320:
1321: /**
1322: * Sets the minimized state for this stack. The part may call this method to
1323: * minimize or restore itself. The minimized state only affects the view
1324: * when unzoomed in the 3.0 presentation (in 3.3 it's handled by the
1325: * ViewStack directly and works as expected).
1326: */
1327: public void setMinimized(boolean minimized) {
1328: if (minimized != isMinimized) {
1329: isMinimized = minimized;
1330:
1331: refreshPresentationState();
1332: }
1333: }
1334:
1335: /* (non-Javadoc)
1336: * @see org.eclipse.ui.internal.ILayoutContainer#obscuredByZoom(org.eclipse.ui.internal.LayoutPart)
1337: */
1338: public boolean childObscuredByZoom(LayoutPart toTest) {
1339: return isObscuredByZoom();
1340: }
1341:
1342: /* (non-Javadoc)
1343: * @see org.eclipse.ui.internal.LayoutPart#requestZoom(org.eclipse.ui.internal.LayoutPart)
1344: */
1345: public void childRequestZoomIn(LayoutPart toZoom) {
1346: super .childRequestZoomIn(toZoom);
1347:
1348: requestZoomIn();
1349: }
1350:
1351: /* (non-Javadoc)
1352: * @see org.eclipse.ui.internal.LayoutPart#requestZoomOut()
1353: */
1354: public void childRequestZoomOut() {
1355: super .childRequestZoomOut();
1356:
1357: requestZoomOut();
1358: }
1359:
1360: /* (non-Javadoc)
1361: * @see org.eclipse.ui.internal.ILayoutContainer#isZoomed(org.eclipse.ui.internal.LayoutPart)
1362: */
1363: public boolean childIsZoomed(LayoutPart toTest) {
1364: return isZoomed();
1365: }
1366:
1367: /**
1368: * This is a hack that allows us to preserve the old
1369: * min/max behavior for the stack containing the IntroPart.
1370: * This is required to have the initial Intro (Welcome)
1371: * pane to show correctly but will induce strange
1372: * effects should a user re-locate the part to
1373: * stacks other that its initial one...
1374: *
1375: * @return true if the stack contains the intro
1376: * as a ViewPane (not if it's only a placeholder)
1377: */
1378: private boolean isIntroInStack() {
1379: LayoutPart[] kids = getChildren();
1380: for (int i = 0; i < kids.length; i++) {
1381: if (kids[i] instanceof ViewPane) {
1382: ViewPane vp = (ViewPane) kids[i];
1383: if (vp.getID().equals(IIntroConstants.INTRO_VIEW_ID))
1384: return true;
1385: }
1386: }
1387: return false;
1388: }
1389:
1390: private void smartZoom() {
1391: WorkbenchWindow wbw = (WorkbenchWindow) getPage()
1392: .getWorkbenchWindow();
1393: if (wbw == null || wbw.getShell() == null)
1394: return;
1395:
1396: Perspective perspective = getPage().getActivePerspective();
1397: FastViewManager fvm = perspective.getFastViewManager();
1398:
1399: fvm.deferUpdates(true);
1400:
1401: // Cache the layout bounds
1402: perspective.getPresentation().updateBoundsMap();
1403:
1404: LayoutPart[] children = perspective.getPresentation()
1405: .getLayout().getChildren();
1406: for (int i = 0; i < children.length; i++) {
1407: if (children[i] != this ) {
1408: if (children[i] instanceof ViewStack) {
1409: ((ViewStack) children[i]).setMinimized(true);
1410: ViewStackTrimToolBar vstb = fvm
1411: .getViewStackTrimToolbar(children[i]
1412: .getID());
1413: vstb.setRestoreOnUnzoom(true);
1414: } else if (children[i] instanceof EditorSashContainer
1415: && !(this instanceof EditorStack)) {
1416: perspective
1417: .setEditorAreaState(IStackPresentationSite.STATE_MINIMIZED);
1418: perspective.setEditorAreaRestoreOnUnzoom(true);
1419: }
1420: }
1421: }
1422:
1423: // If the editor area has changed state tell the perspective
1424: if (this instanceof EditorStack)
1425: perspective
1426: .setEditorAreaState(IStackPresentationSite.STATE_MAXIMIZED);
1427:
1428: // Clear the boundsMap
1429: perspective.getPresentation().resetBoundsMap();
1430:
1431: // We're done batching...
1432: fvm.deferUpdates(false);
1433:
1434: perspective.getPresentation().setMaximizedStack(this );
1435: smartZoomed = true;
1436: }
1437:
1438: protected void smartUnzoom() {
1439: // Prevent recursion through 'setMinimized'
1440: if (doingUnzoom)
1441: return;
1442: doingUnzoom = true;
1443:
1444: WorkbenchWindow wbw = (WorkbenchWindow) getPage()
1445: .getWorkbenchWindow();
1446: if (wbw == null || wbw.getShell() == null)
1447: return;
1448:
1449: ITrimManager tbm = wbw.getTrimManager();
1450: Perspective perspective = getPage().getActivePerspective();
1451: FastViewManager fvm = perspective.getFastViewManager();
1452:
1453: ILayoutContainer root = getContainer();
1454:
1455: // We go up one more level when maximizing an editor stack
1456: // so that we 'zoom' the editor area
1457: boolean restoringEditorArea = false;
1458: if (root instanceof EditorSashContainer) {
1459: root = ((EditorSashContainer) root).getContainer();
1460: restoringEditorArea = true;
1461: }
1462:
1463: // This is a compound operation
1464: fvm.deferUpdates(true);
1465:
1466: LayoutPart[] children = root.getChildren();
1467: for (int i = 0; i < children.length; i++) {
1468: if (children[i] != this ) {
1469: IWindowTrim trim = tbm.getTrim(children[i].getID());
1470: if (trim == null)
1471: continue;
1472:
1473: if (trim instanceof ViewStackTrimToolBar) {
1474: ViewStackTrimToolBar vstb = (ViewStackTrimToolBar) trim;
1475: if (vstb.restoreOnUnzoom()
1476: && children[i] instanceof ContainerPlaceholder) {
1477: // In the current presentation its a
1478: // container placeholder
1479: ViewStack realStack = (ViewStack) ((ContainerPlaceholder) children[i])
1480: .getRealContainer();
1481: realStack.setMinimized(false);
1482:
1483: vstb.setRestoreOnUnzoom(false);
1484: }
1485: } else if (trim instanceof EditorAreaTrimToolBar) {
1486: if (perspective.getEditorAreaRestoreOnUnzoom())
1487: perspective
1488: .setEditorAreaState(IStackPresentationSite.STATE_RESTORED);
1489: }
1490: }
1491: }
1492:
1493: // If the editor area has changed state tell the perspective
1494: if (restoringEditorArea)
1495: perspective
1496: .setEditorAreaState(IStackPresentationSite.STATE_RESTORED);
1497:
1498: perspective.getPresentation().setMaximizedStack(null);
1499:
1500: fvm.deferUpdates(false);
1501: smartZoomed = false;
1502:
1503: doingUnzoom = false;
1504: }
1505:
1506: protected void setState(final int newState) {
1507: final int oldState = presentationSite.getState();
1508: if (!supportsState(newState) || newState == oldState) {
1509: return;
1510: }
1511:
1512: final WorkbenchWindow wbw = (WorkbenchWindow) getPage()
1513: .getWorkbenchWindow();
1514: if (wbw == null || wbw.getShell() == null
1515: || wbw.getActiveWorkbenchPage() == null)
1516: return;
1517:
1518: WorkbenchPage page = wbw.getActiveWorkbenchPage();
1519: if (page == null)
1520: return;
1521:
1522: boolean useNewMinMax = Perspective.useNewMinMax(page
1523: .getActivePerspective());
1524:
1525: // we have to fiddle with the zoom behavior to satisfy Intro req's
1526: // by usning the old zoom behavior for its stack
1527: if (newState == IStackPresentationSite.STATE_MAXIMIZED)
1528: useNewMinMax = useNewMinMax && !isIntroInStack();
1529: else if (newState == IStackPresentationSite.STATE_RESTORED) {
1530: PartStack maxStack = page.getActivePerspective()
1531: .getPresentation().getMaximizedStack();
1532: useNewMinMax = useNewMinMax && maxStack == this ;
1533: }
1534:
1535: if (useNewMinMax) {
1536: StartupThreading
1537: .runWithoutExceptions(new StartupRunnable() {
1538: public void runWithException() throws Throwable {
1539: wbw.getPageComposite().setRedraw(false);
1540: try {
1541: if (newState == IStackPresentationSite.STATE_MAXIMIZED) {
1542: smartZoom();
1543: } else if (oldState == IStackPresentationSite.STATE_MAXIMIZED) {
1544: smartUnzoom();
1545: }
1546:
1547: if (newState == IStackPresentationSite.STATE_MINIMIZED) {
1548: setMinimized(true);
1549: }
1550: } finally {
1551: wbw.getPageComposite().setRedraw(true);
1552:
1553: // Force a redraw (fixes Mac refresh)
1554: wbw.getShell().redraw();
1555: }
1556:
1557: setPresentationState(newState);
1558: }
1559: });
1560: } else {
1561: boolean minimized = (newState == IStackPresentationSite.STATE_MINIMIZED);
1562: setMinimized(minimized);
1563:
1564: if (newState == IStackPresentationSite.STATE_MAXIMIZED) {
1565: requestZoomIn();
1566: } else if (oldState == IStackPresentationSite.STATE_MAXIMIZED) {
1567: requestZoomOut();
1568:
1569: if (newState == IStackPresentationSite.STATE_MINIMIZED)
1570: setMinimized(true);
1571: }
1572: }
1573: }
1574:
1575: /**
1576: * Called by the workbench page to notify this part that it has been zoomed or unzoomed.
1577: * The PartStack should not call this method itself -- it must request zoom changes by
1578: * talking to the WorkbenchPage.
1579: */
1580: public void setZoomed(boolean isZoomed) {
1581:
1582: super .setZoomed(isZoomed);
1583:
1584: LayoutPart[] children = getChildren();
1585:
1586: for (int i = 0; i < children.length; i++) {
1587: LayoutPart next = children[i];
1588:
1589: next.setZoomed(isZoomed);
1590: }
1591:
1592: refreshPresentationState();
1593: }
1594:
1595: public boolean isZoomed() {
1596: ILayoutContainer container = getContainer();
1597:
1598: if (container != null) {
1599: return container.childIsZoomed(this );
1600: }
1601:
1602: return false;
1603: }
1604:
1605: protected void refreshPresentationState() {
1606: if (isZoomed() || smartZoomed) {
1607: presentationSite
1608: .setPresentationState(IStackPresentationSite.STATE_MAXIMIZED);
1609: } else {
1610:
1611: boolean wasMinimized = (presentationSite.getState() == IStackPresentationSite.STATE_MINIMIZED);
1612:
1613: if (isMinimized) {
1614: presentationSite
1615: .setPresentationState(IStackPresentationSite.STATE_MINIMIZED);
1616: } else {
1617: presentationSite
1618: .setPresentationState(IStackPresentationSite.STATE_RESTORED);
1619: }
1620:
1621: if (isMinimized != wasMinimized) {
1622: flushLayout();
1623:
1624: if (isMinimized) {
1625: WorkbenchPage page = getPage();
1626:
1627: if (page != null) {
1628: page.refreshActiveView();
1629: }
1630: }
1631: }
1632: }
1633: }
1634:
1635: /**
1636: * Makes the given part visible in the presentation.
1637: * @param part the part to add to the stack
1638: * @param cookie other information
1639: */
1640: private void showPart(LayoutPart part, Object cookie) {
1641:
1642: if (isDisposed()) {
1643: return;
1644: }
1645:
1646: if ((part instanceof PartPlaceholder)) {
1647: part.setContainer(this );
1648: return;
1649: }
1650:
1651: if (!(part instanceof PartPane)) {
1652: WorkbenchPlugin.log(NLS.bind(
1653: WorkbenchMessages.PartStack_incorrectPartInFolder,
1654: part.getID()));
1655: return;
1656: }
1657:
1658: PartPane pane = (PartPane) part;
1659:
1660: PresentablePart presentablePart = new PresentablePart(pane,
1661: getControl().getParent());
1662: presentableParts.add(presentablePart);
1663:
1664: if (isActive) {
1665: part.setContainer(this );
1666: }
1667:
1668: presentationSite.getPresentation().addPart(presentablePart,
1669: cookie);
1670:
1671: if (requestedCurrent == null) {
1672: setSelection(part);
1673: }
1674:
1675: if (childObscuredByZoom(part)) {
1676: presentablePart.enableInputs(false);
1677: }
1678: }
1679:
1680: /**
1681: * Update the container to show the correct visible tab based on the
1682: * activation list.
1683: */
1684: private void updateContainerVisibleTab() {
1685: LayoutPart[] parts = getChildren();
1686:
1687: if (parts.length < 1) {
1688: setSelection(null);
1689: return;
1690: }
1691:
1692: PartPane selPart = null;
1693: int topIndex = 0;
1694: WorkbenchPage page = getPage();
1695:
1696: if (page != null) {
1697: IWorkbenchPartReference sortedPartsArray[] = page
1698: .getSortedParts();
1699: List sortedParts = Arrays.asList(sortedPartsArray);
1700: for (int i = 0; i < parts.length; i++) {
1701: if (parts[i] instanceof PartPane) {
1702: IWorkbenchPartReference part = ((PartPane) parts[i])
1703: .getPartReference();
1704: int index = sortedParts.indexOf(part);
1705: if (index >= topIndex) {
1706: topIndex = index;
1707: selPart = (PartPane) parts[i];
1708: }
1709: }
1710: }
1711:
1712: }
1713:
1714: if (selPart == null) {
1715: List presentableParts = getPresentableParts();
1716: if (presentableParts.size() != 0) {
1717: IPresentablePart part = (IPresentablePart) getPresentableParts()
1718: .get(0);
1719:
1720: selPart = (PartPane) getPaneFor(part);
1721: }
1722: }
1723:
1724: setSelection(selPart);
1725: }
1726:
1727: /**
1728: *
1729: */
1730: public void showSystemMenu() {
1731: getPresentation().showSystemMenu();
1732: }
1733:
1734: public void showPaneMenu() {
1735: getPresentation().showPaneMenu();
1736: }
1737:
1738: public void showPartList() {
1739: getPresentation().showPartList();
1740: }
1741:
1742: public Control[] getTabList(LayoutPart part) {
1743: if (part != null) {
1744: IPresentablePart presentablePart = getPresentablePart(part);
1745: StackPresentation presentation = getPresentation();
1746:
1747: if (presentablePart != null && presentation != null) {
1748: return presentation.getTabList(presentablePart);
1749: }
1750: }
1751:
1752: return new Control[0];
1753: }
1754:
1755: /**
1756: *
1757: * @param beingDragged
1758: * @param initialLocation
1759: * @param keyboard
1760: */
1761: private void dragStart(IPresentablePart beingDragged,
1762: Point initialLocation, boolean keyboard) {
1763: if (beingDragged == null) {
1764: paneDragStart((LayoutPart) null, initialLocation, keyboard);
1765: } else {
1766: if (presentationSite.isPartMoveable(beingDragged)) {
1767: LayoutPart pane = getPaneFor(beingDragged);
1768:
1769: if (pane != null) {
1770: paneDragStart(pane, initialLocation, keyboard);
1771: }
1772: }
1773: }
1774: }
1775:
1776: public void paneDragStart(LayoutPart pane, Point initialLocation,
1777: boolean keyboard) {
1778: if (pane == null) {
1779: if (canMoveFolder()) {
1780:
1781: if (presentationSite.getState() == IStackPresentationSite.STATE_MAXIMIZED) {
1782: // Calculate where the initial location was BEFORE the 'restore'...as a percentage
1783: Rectangle bounds = Geometry.toDisplay(getParent(),
1784: getPresentation().getControl().getBounds());
1785: float xpct = (initialLocation.x - bounds.x)
1786: / (float) (bounds.width);
1787: float ypct = (initialLocation.y - bounds.y)
1788: / (float) (bounds.height);
1789:
1790: setState(IStackPresentationSite.STATE_RESTORED);
1791:
1792: // Now, adjust the initial location to be within the bounds of the restored rect
1793: bounds = Geometry.toDisplay(getParent(),
1794: getPresentation().getControl().getBounds());
1795: initialLocation.x = (int) (bounds.x + (xpct * bounds.width));
1796: initialLocation.y = (int) (bounds.y + (ypct * bounds.height));
1797: }
1798:
1799: DragUtil.performDrag(PartStack.this , Geometry
1800: .toDisplay(getParent(), getPresentation()
1801: .getControl().getBounds()),
1802: initialLocation, !keyboard);
1803: }
1804: } else {
1805:
1806: if (presentationSite.getState() == IStackPresentationSite.STATE_MAXIMIZED) {
1807: // Calculate where the initial location was BEFORE the 'restore'...as a percentage
1808: Rectangle bounds = Geometry.toDisplay(getParent(),
1809: getPresentation().getControl().getBounds());
1810: float xpct = (initialLocation.x - bounds.x)
1811: / (float) (bounds.width);
1812: float ypct = (initialLocation.y - bounds.y)
1813: / (float) (bounds.height);
1814:
1815: presentationSite
1816: .setState(IStackPresentationSite.STATE_RESTORED);
1817:
1818: // Now, adjust the initial location to be within the bounds of the restored rect
1819: // See bug 100908
1820: bounds = Geometry.toDisplay(getParent(),
1821: getPresentation().getControl().getBounds());
1822: initialLocation.x = (int) (bounds.x + (xpct * bounds.width));
1823: initialLocation.y = (int) (bounds.y + (ypct * bounds.height));
1824: }
1825:
1826: DragUtil.performDrag(pane, Geometry.toDisplay(getParent(),
1827: getPresentation().getControl().getBounds()),
1828: initialLocation, !keyboard);
1829: }
1830: }
1831:
1832: /**
1833: * @return Returns the savedPresentationState.
1834: */
1835: public IMemento getSavedPresentationState() {
1836: return savedPresentationState;
1837: }
1838:
1839: private void fireInternalPropertyChange(int id) {
1840: Object listeners[] = this .listeners.getListeners();
1841: for (int i = 0; i < listeners.length; i++) {
1842: ((IPropertyListener) listeners[i])
1843: .propertyChanged(this , id);
1844: }
1845: }
1846:
1847: // TrimStack Support
1848:
1849: /**
1850: * Explicitly sets the presentation state. This is used by the
1851: * new min/max code to force the CTabFolder to show the proper
1852: * state without going through the 'setState' code (which causes
1853: * nasty side-effects.
1854: * @param newState The state to set the presentation to
1855: */
1856: public void setPresentationState(int newState) {
1857: presentationSite.setPresentationState(newState);
1858: }
1859:
1860: //
1861: // Support for passing perspective layout properties to the presentation
1862:
1863: public String getProperty(String id) {
1864: return (String) properties.get(id);
1865: }
1866:
1867: public void setProperty(String id, String value) {
1868: if (value == null) {
1869: properties.remove(id);
1870: } else {
1871: properties.put(id, value);
1872: }
1873: }
1874:
1875: /**
1876: * Copies all appearance related data from this stack to the given stack.
1877: */
1878: public void copyAppearanceProperties(PartStack copyTo) {
1879: copyTo.appearance = this .appearance;
1880: if (!properties.isEmpty()) {
1881: Set ids = properties.keySet();
1882: for (Iterator iterator = ids.iterator(); iterator.hasNext();) {
1883: String id = (String) iterator.next();
1884: copyTo.setProperty(id, (String) properties.get(id));
1885: }
1886: }
1887: }
1888: }
|