0001: /*******************************************************************************
0002: * Copyright (c) 2000, 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: *******************************************************************************/package org.eclipse.ui.internal;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Collections;
0014: import java.util.Enumeration;
0015: import java.util.HashMap;
0016: import java.util.List;
0017: import java.util.Map;
0018: import java.util.Vector;
0019:
0020: import org.eclipse.core.runtime.IStatus;
0021: import org.eclipse.jface.preference.IPreferenceStore;
0022: import org.eclipse.swt.SWT;
0023: import org.eclipse.swt.graphics.Cursor;
0024: import org.eclipse.swt.graphics.Point;
0025: import org.eclipse.swt.graphics.Rectangle;
0026: import org.eclipse.swt.widgets.Composite;
0027: import org.eclipse.swt.widgets.Control;
0028: import org.eclipse.swt.widgets.Shell;
0029: import org.eclipse.ui.IMemento;
0030: import org.eclipse.ui.IViewReference;
0031: import org.eclipse.ui.IWorkbenchPartReference;
0032: import org.eclipse.ui.IWorkbenchPreferenceConstants;
0033: import org.eclipse.ui.PlatformUI;
0034: import org.eclipse.ui.internal.dnd.AbstractDropTarget;
0035: import org.eclipse.ui.internal.dnd.DragUtil;
0036: import org.eclipse.ui.internal.dnd.IDragOverListener;
0037: import org.eclipse.ui.internal.dnd.IDropTarget;
0038: import org.eclipse.ui.internal.misc.StringMatcher;
0039: import org.eclipse.ui.presentations.IStackPresentationSite;
0040:
0041: /**
0042: * A perspective presentation is a collection of parts with a layout. Each part
0043: * is parented to a main window, so you can create more than one presentation
0044: * on a set of parts and change the layout just by activating / deactivating a
0045: * presentation.
0046: *
0047: * In addition, the user can change the position of any part by mouse
0048: * manipulation (drag & drop). If a part is removed, we leave a placeholder
0049: * behind to indicate where it goes should the part be added back.
0050: */
0051: public class PerspectiveHelper {
0052: private WorkbenchPage page;
0053:
0054: private Perspective perspective;
0055:
0056: private Composite parentWidget;
0057:
0058: private ViewSashContainer mainLayout;
0059:
0060: private PartStack maximizedStack;
0061:
0062: /**
0063: * If there is a ViewStack maximized on shutdown the id is
0064: * cached and restored into this field on 'restoreState'.
0065: * This is then used to bash the ViewStack's presentation state
0066: * into the correct value on activation (the startup life-cycle
0067: * is such that we have to use this 'latch' because the window
0068: * state isn't valid until the activate happens.
0069: */
0070: private String maximizedStackId;
0071:
0072: private ArrayList detachedWindowList = new ArrayList(1);
0073:
0074: private ArrayList detachedPlaceHolderList = new ArrayList(1);
0075:
0076: /**
0077: * Maps a stack's id to its current bounds
0078: * this is used to capture the current bounds of all
0079: * stacks -before- starting a maximize (since the
0080: * iterative 'minimize' calls cause the intial stack's
0081: * bounds to change.
0082: */
0083: private Map boundsMap = new HashMap();
0084:
0085: private boolean detachable = false;
0086:
0087: private boolean active = false;
0088:
0089: // key is the LayoutPart object, value is the PartDragDrop object
0090: //private IPartDropListener partDropListener;
0091:
0092: private static final int MIN_DETACH_WIDTH = 150;
0093:
0094: private static final int MIN_DETACH_HEIGHT = 250;
0095:
0096: protected ActualDropTarget dropTarget;
0097:
0098: private IDragOverListener dragTarget = new IDragOverListener() {
0099:
0100: public IDropTarget drag(Control currentControl,
0101: Object draggedObject, Point position,
0102: final Rectangle dragRectangle) {
0103:
0104: if (!(draggedObject instanceof ViewPane || draggedObject instanceof ViewStack)) {
0105: return null;
0106: }
0107: final LayoutPart part = (LayoutPart) draggedObject;
0108:
0109: if (part.getWorkbenchWindow() != page.getWorkbenchWindow()) {
0110: return null;
0111: }
0112:
0113: if (dropTarget == null) {
0114: dropTarget = new ActualDropTarget(part, dragRectangle);
0115: } else {
0116: dropTarget.setTarget(part, dragRectangle);
0117: }
0118:
0119: return dropTarget;
0120: }
0121:
0122: };
0123:
0124: private final class ActualDropTarget extends AbstractDropTarget {
0125: private LayoutPart part;
0126:
0127: private Rectangle dragRectangle;
0128:
0129: private ActualDropTarget(LayoutPart part,
0130: Rectangle dragRectangle) {
0131: super ();
0132: setTarget(part, dragRectangle);
0133: }
0134:
0135: /**
0136: * @param part
0137: * @param dragRectangle
0138: * @since 3.1
0139: */
0140: private void setTarget(LayoutPart part, Rectangle dragRectangle) {
0141: this .part = part;
0142: this .dragRectangle = dragRectangle;
0143: }
0144:
0145: public void drop() {
0146:
0147: Shell shell = part.getShell();
0148: if (shell.getData() instanceof DetachedWindow) {
0149: // only one tab folder in a detach window, so do window
0150: // move
0151: if (part instanceof ViewStack) {
0152: shell.setLocation(dragRectangle.x, dragRectangle.y);
0153: return;
0154: }
0155: // if only one view in tab folder then do a window move
0156: ILayoutContainer container = part.getContainer();
0157: if (container instanceof ViewStack) {
0158: if (((ViewStack) container).getItemCount() == 1) {
0159: shell.setLocation(dragRectangle.x,
0160: dragRectangle.y);
0161: return;
0162: }
0163: }
0164: }
0165:
0166: // If layout is modified always zoom out.
0167: if (isZoomed()) {
0168: zoomOut();
0169: }
0170: // do a normal part detach
0171: detach(part, dragRectangle.x, dragRectangle.y);
0172: }
0173:
0174: public Cursor getCursor() {
0175: return DragCursors.getCursor(DragCursors.OFFSCREEN);
0176: }
0177: }
0178:
0179: private class MatchingPart implements Comparable {
0180: String pid;
0181:
0182: String sid;
0183:
0184: LayoutPart part;
0185:
0186: boolean hasWildcard;
0187:
0188: int len;
0189:
0190: MatchingPart(String pid, String sid, LayoutPart part) {
0191: this .pid = pid;
0192: this .sid = sid;
0193: this .part = part;
0194: this .len = (pid == null ? 0 : pid.length())
0195: + (sid == null ? 0 : sid.length());
0196: this .hasWildcard = (pid != null && pid
0197: .indexOf(PartPlaceholder.WILD_CARD) != -1)
0198: || (sid != null && sid
0199: .indexOf(PartPlaceholder.WILD_CARD) != -1);
0200: }
0201:
0202: public int compareTo(Object a) {
0203: // specific ids always outweigh ids with wildcards
0204: MatchingPart ma = (MatchingPart) a;
0205: if (this .hasWildcard && !ma.hasWildcard) {
0206: return -1;
0207: }
0208: if (!this .hasWildcard && ma.hasWildcard) {
0209: return 1;
0210: }
0211: // if both are specific or both have wildcards, simply compare based on length
0212: return ma.len - this .len;
0213: }
0214: }
0215:
0216: /**
0217: * Constructs a new object.
0218: */
0219: public PerspectiveHelper(WorkbenchPage workbenchPage,
0220: ViewSashContainer mainLayout, Perspective perspective) {
0221: this .page = workbenchPage;
0222: this .mainLayout = mainLayout;
0223: this .perspective = perspective;
0224:
0225: // Views can be detached if the feature is enabled (true by default,
0226: // use the plug-in customization file to disable), and if the platform
0227: // supports detaching.
0228:
0229: final IPreferenceStore store = PlatformUI.getPreferenceStore();
0230: this .detachable = store
0231: .getBoolean(IWorkbenchPreferenceConstants.ENABLE_DETACHED_VIEWS);
0232:
0233: if (this .detachable) {
0234: // Check if some arbitrary Composite supports reparenting. If it
0235: // doesn't, views cannot be detached.
0236:
0237: Composite client = workbenchPage.getClientComposite();
0238: if (client == null) {
0239: // The workbench page is not initialized. I don't think this can happen,
0240: // but if it does, silently set detachable to false.
0241: this .detachable = false;
0242: } else {
0243: Composite testChild = new Composite(client, SWT.NONE);
0244: this .detachable = testChild.isReparentable();
0245: testChild.dispose();
0246: }
0247: }
0248: }
0249:
0250: /**
0251: * Show the presentation.
0252: */
0253: public void activate(Composite parent) {
0254:
0255: if (active) {
0256: return;
0257: }
0258:
0259: parentWidget = parent;
0260:
0261: // Activate main layout
0262: // make sure all the views have been properly parented
0263: Vector children = new Vector();
0264: collectViewPanes(children, mainLayout.getChildren());
0265: Enumeration itr = children.elements();
0266: while (itr.hasMoreElements()) {
0267: LayoutPart part = (LayoutPart) itr.nextElement();
0268: part.reparent(parent);
0269: }
0270: mainLayout.createControl(parent);
0271: mainLayout.setActive(true);
0272:
0273: // Open the detached windows.
0274: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0275: DetachedWindow dwindow = (DetachedWindow) detachedWindowList
0276: .get(i);
0277: dwindow.open();
0278: }
0279:
0280: enableAllDrag();
0281:
0282: // Ensure that the maximized stack's presentation state is correct
0283: if (maximizedStackId != null) {
0284: LayoutPart part = findPart(maximizedStackId);
0285: if (part instanceof PartStack) {
0286: maximizedStack = (PartStack) part;
0287: maximizedStackId = null;
0288: }
0289: }
0290:
0291: // NOTE: we only handle ViewStacks here; Editor Stacks are handled by the
0292: // perspective
0293: if (maximizedStack instanceof ViewStack) {
0294: maximizedStack
0295: .setPresentationState(IStackPresentationSite.STATE_MAXIMIZED);
0296: }
0297:
0298: active = true;
0299: }
0300:
0301: /**
0302: * Adds a part to the presentation. If a placeholder exists for the part
0303: * then swap the part in. Otherwise, add the part in the bottom right
0304: * corner of the presentation.
0305: */
0306: public void addPart(LayoutPart part) {
0307:
0308: // Look for a placeholder.
0309: PartPlaceholder placeholder = null;
0310: LayoutPart testPart = null;
0311: String primaryId = part.getID();
0312: String secondaryId = null;
0313:
0314: IViewReference ref = null;
0315: if (part instanceof ViewPane) {
0316: ViewPane pane = (ViewPane) part;
0317: ref = (IViewReference) pane.getPartReference();
0318: secondaryId = ref.getSecondaryId();
0319: }
0320: if (secondaryId != null) {
0321: testPart = findPart(primaryId, secondaryId);
0322: } else {
0323: testPart = findPart(primaryId);
0324: }
0325:
0326: // validate the testPart
0327: if (testPart != null && testPart instanceof PartPlaceholder) {
0328: placeholder = (PartPlaceholder) testPart;
0329: }
0330:
0331: // If there is no placeholder do a simple add. Otherwise, replace the
0332: // placeholder if its not a pattern matching placholder
0333: if (placeholder == null) {
0334: part.reparent(mainLayout.getParent());
0335: LayoutPart relative = mainLayout.findBottomRight();
0336: if (relative != null
0337: && relative instanceof ILayoutContainer) {
0338: ILayoutContainer stack = (ILayoutContainer) relative;
0339: if (stack.allowsAdd(part)) {
0340: mainLayout.stack(part, stack);
0341: } else {
0342: mainLayout.add(part);
0343: }
0344: } else {
0345: mainLayout.add(part);
0346: }
0347: } else {
0348: ILayoutContainer container = placeholder.getContainer();
0349: if (container != null) {
0350: if (container instanceof DetachedPlaceHolder) {
0351: //Create a detached window add the part on it.
0352: DetachedPlaceHolder holder = (DetachedPlaceHolder) container;
0353: detachedPlaceHolderList.remove(holder);
0354: container.remove(testPart);
0355: DetachedWindow window = new DetachedWindow(page);
0356: detachedWindowList.add(window);
0357: window.create();
0358: part.createControl(window.getShell());
0359: // Open window.
0360: window.getShell().setBounds(holder.getBounds());
0361: window.open();
0362: // add part to detached window.
0363: ViewPane pane = (ViewPane) part;
0364: window.add(pane);
0365: LayoutPart otherChildren[] = holder.getChildren();
0366: for (int i = 0; i < otherChildren.length; i++) {
0367: part.getContainer().add(otherChildren[i]);
0368: }
0369: } else {
0370: // show parent if necessary
0371: if (container instanceof ContainerPlaceholder) {
0372: ContainerPlaceholder containerPlaceholder = (ContainerPlaceholder) container;
0373: ILayoutContainer parentContainer = containerPlaceholder
0374: .getContainer();
0375: container = (ILayoutContainer) containerPlaceholder
0376: .getRealContainer();
0377: if (container instanceof LayoutPart) {
0378: parentContainer.replace(
0379: containerPlaceholder,
0380: (LayoutPart) container);
0381: }
0382: containerPlaceholder.setRealContainer(null);
0383: }
0384:
0385: // reparent part.
0386: if (!(container instanceof ViewStack)) {
0387: // We don't need to reparent children of PartTabFolders since they will automatically
0388: // reparent their children when they become visible. This if statement used to be
0389: // part of an else branch. Investigate if it is still necessary.
0390: part.reparent(mainLayout.getParent());
0391: }
0392:
0393: // see if we should replace the placeholder
0394: if (placeholder.hasWildCard()) {
0395: if (container instanceof PartSashContainer) {
0396: ((PartSashContainer) container)
0397: .addChildForPlaceholder(part,
0398: placeholder);
0399: } else {
0400: container.add(part);
0401: }
0402: } else {
0403: container.replace(placeholder, part);
0404: }
0405: }
0406: }
0407: }
0408: }
0409:
0410: /**
0411: * Attaches a part that was previously detached to the mainLayout.
0412: *
0413: * @param ref
0414: */
0415: public void attachPart(IViewReference ref) {
0416: ViewPane pane = (ViewPane) ((WorkbenchPartReference) ref)
0417: .getPane();
0418:
0419: // Restore any maximized part before re-attaching.
0420: // Note that 'getMaximizedStack != null' implies 'useNewMinMax'
0421: if (getMaximizedStack() != null) {
0422: getMaximizedStack().setState(
0423: IStackPresentationSite.STATE_RESTORED);
0424: }
0425:
0426: derefPart(pane);
0427: addPart(pane);
0428: bringPartToTop(pane);
0429: pane.setFocus();
0430: }
0431:
0432: /**
0433: * Return whether detachable parts can be supported.
0434: */
0435: public boolean canDetach() {
0436: return detachable;
0437: }
0438:
0439: /**
0440: * Bring a part forward so it is visible.
0441: *
0442: * @return true if the part was brought to top, false if not.
0443: */
0444: public boolean bringPartToTop(LayoutPart part) {
0445: ILayoutContainer container = part.getContainer();
0446: if (container != null && container instanceof PartStack) {
0447: PartStack folder = (PartStack) container;
0448: if (folder.getSelection() != part) {
0449: folder.setSelection(part);
0450: return true;
0451: }
0452: }
0453: return false;
0454: }
0455:
0456: /**
0457: * Returns true if the given part is visible.
0458: * A part is visible if it's top-level (not in a tab folder) or if it is the top one
0459: * in a tab folder.
0460: */
0461: public boolean isPartVisible(IWorkbenchPartReference partRef) {
0462: LayoutPart foundPart;
0463: if (partRef instanceof IViewReference) {
0464: foundPart = findPart(partRef.getId(),
0465: ((IViewReference) partRef).getSecondaryId());
0466: } else {
0467: foundPart = findPart(partRef.getId());
0468: }
0469: if (foundPart == null) {
0470: return false;
0471: }
0472: if (foundPart instanceof PartPlaceholder) {
0473: return false;
0474: }
0475:
0476: ILayoutContainer container = foundPart.getContainer();
0477:
0478: if (container instanceof ContainerPlaceholder) {
0479: return false;
0480: }
0481:
0482: if (container instanceof ViewStack) {
0483: ViewStack folder = (ViewStack) container;
0484: PartPane visiblePart = folder.getSelection();
0485: if (visiblePart == null) {
0486: return false;
0487: }
0488: return partRef.equals(visiblePart.getPartReference());
0489: }
0490: return true;
0491: }
0492:
0493: /**
0494: * Returns true is not in a tab folder or if it is the top one in a tab
0495: * folder.
0496: */
0497: public boolean willPartBeVisible(String partId) {
0498: return willPartBeVisible(partId, null);
0499: }
0500:
0501: public boolean willPartBeVisible(String partId, String secondaryId) {
0502: LayoutPart part = findPart(partId, secondaryId);
0503: if (part == null) {
0504: return false;
0505: }
0506: ILayoutContainer container = part.getContainer();
0507: if (container != null
0508: && container instanceof ContainerPlaceholder) {
0509: container = (ILayoutContainer) ((ContainerPlaceholder) container)
0510: .getRealContainer();
0511: }
0512:
0513: if (container != null && container instanceof ViewStack) {
0514: ViewStack folder = (ViewStack) container;
0515: if (folder.getSelection() == null) {
0516: return false;
0517: }
0518: return part.getCompoundId().equals(
0519: folder.getSelection().getCompoundId());
0520: }
0521: return true;
0522: }
0523:
0524: /**
0525: * Answer a list of the PartPlaceholder objects.
0526: */
0527: private PartPlaceholder[] collectPlaceholders() {
0528: // Scan the main window.
0529: PartPlaceholder[] results = collectPlaceholders(mainLayout
0530: .getChildren());
0531:
0532: // Scan each detached window.
0533: if (detachable) {
0534: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0535: DetachedWindow win = (DetachedWindow) detachedWindowList
0536: .get(i);
0537: PartPlaceholder[] moreResults = collectPlaceholders(win
0538: .getChildren());
0539: if (moreResults.length > 0) {
0540: int newLength = results.length + moreResults.length;
0541: PartPlaceholder[] newResults = new PartPlaceholder[newLength];
0542: System.arraycopy(results, 0, newResults, 0,
0543: results.length);
0544: System.arraycopy(moreResults, 0, newResults,
0545: results.length, moreResults.length);
0546: results = newResults;
0547: }
0548: }
0549: }
0550: return results;
0551: }
0552:
0553: /**
0554: * Answer a list of the PartPlaceholder objects.
0555: */
0556: private PartPlaceholder[] collectPlaceholders(LayoutPart[] parts) {
0557: PartPlaceholder[] result = new PartPlaceholder[0];
0558:
0559: for (int i = 0, length = parts.length; i < length; i++) {
0560: LayoutPart part = parts[i];
0561: if (part instanceof ILayoutContainer) {
0562: // iterate through sub containers to find sub-parts
0563: PartPlaceholder[] newParts = collectPlaceholders(((ILayoutContainer) part)
0564: .getChildren());
0565: PartPlaceholder[] newResult = new PartPlaceholder[result.length
0566: + newParts.length];
0567: System
0568: .arraycopy(result, 0, newResult, 0,
0569: result.length);
0570: System.arraycopy(newParts, 0, newResult, result.length,
0571: newParts.length);
0572: result = newResult;
0573: } else if (part instanceof PartPlaceholder) {
0574: PartPlaceholder[] newResult = new PartPlaceholder[result.length + 1];
0575: System
0576: .arraycopy(result, 0, newResult, 0,
0577: result.length);
0578: newResult[result.length] = (PartPlaceholder) part;
0579: result = newResult;
0580: }
0581: }
0582:
0583: return result;
0584: }
0585:
0586: /**
0587: * Answer a list of the view panes.
0588: */
0589: public void collectViewPanes(List result) {
0590: // Scan the main window.
0591: collectViewPanes(result, mainLayout.getChildren());
0592:
0593: // Scan each detached window.
0594: if (detachable) {
0595: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0596: DetachedWindow win = (DetachedWindow) detachedWindowList
0597: .get(i);
0598: collectViewPanes(result, win.getChildren());
0599: }
0600: }
0601: }
0602:
0603: /**
0604: * Answer a list of the view panes.
0605: */
0606: private void collectViewPanes(List result, LayoutPart[] parts) {
0607: for (int i = 0, length = parts.length; i < length; i++) {
0608: LayoutPart part = parts[i];
0609: if (part instanceof ViewPane) {
0610: result.add(part);
0611: } else if (part instanceof ILayoutContainer) {
0612: collectViewPanes(result, ((ILayoutContainer) part)
0613: .getChildren());
0614: }
0615: }
0616: }
0617:
0618: /**
0619: * Hide the presentation.
0620: */
0621: public void deactivate() {
0622: if (!active) {
0623: return;
0624: }
0625:
0626: disableAllDrag();
0627:
0628: // Reparent all views to the main window
0629: Composite parent = mainLayout.getParent();
0630: Vector children = new Vector();
0631: collectViewPanes(children, mainLayout.getChildren());
0632:
0633: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0634: DetachedWindow window = (DetachedWindow) detachedWindowList
0635: .get(i);
0636: collectViewPanes(children, window.getChildren());
0637: }
0638:
0639: // *** Do we even need to do this if detached windows not supported?
0640: Enumeration itr = children.elements();
0641: while (itr.hasMoreElements()) {
0642: LayoutPart part = (LayoutPart) itr.nextElement();
0643: part.reparent(parent);
0644: }
0645:
0646: // Dispose main layout.
0647:
0648: mainLayout.setActive(false);
0649:
0650: // Dispose the detached windows
0651: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0652: DetachedWindow window = (DetachedWindow) detachedWindowList
0653: .get(i);
0654: window.close();
0655: }
0656:
0657: active = false;
0658: }
0659:
0660: public void dispose() {
0661: mainLayout.dispose();
0662: mainLayout.disposeSashes();
0663: }
0664:
0665: /**
0666: * Writes a description of the layout to the given string buffer.
0667: * This is used for drag-drop test suites to determine if two layouts are the
0668: * same. Like a hash code, the description should compare as equal iff the
0669: * layouts are the same. However, it should be user-readable in order to
0670: * help debug failed tests. Although these are english readable strings,
0671: * they should not be translated or equality tests will fail.
0672: * <p>
0673: * This is only intended for use by test suites.
0674: * </p>
0675: *
0676: * @param buf
0677: */
0678: public void describeLayout(StringBuffer buf) {
0679:
0680: if (detachable) {
0681: if (detachedWindowList.size() != 0) {
0682: buf.append("detachedWindows ("); //$NON-NLS-1$
0683:
0684: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
0685: DetachedWindow window = (DetachedWindow) detachedWindowList
0686: .get(i);
0687: LayoutPart[] children = window.getChildren();
0688: if (children.length != 0) {
0689: buf.append("dWindow ("); //$NON-NLS-1$
0690: for (int j = 0; j < children.length; j++) {
0691: buf.append(((ViewPane) children[j])
0692: .getViewReference().getPartName());
0693: if (j < (children.length - 1)) {
0694: buf.append(", "); //$NON-NLS-1$
0695: }
0696: }
0697: buf.append(")"); //$NON-NLS-1$
0698: }
0699:
0700: }
0701: buf.append("), "); //$NON-NLS-1$
0702: }
0703: }
0704:
0705: getLayout().describeLayout(buf);
0706: }
0707:
0708: /**
0709: * Deref a given part. Deconstruct its container as required. Do not remove
0710: * drag listeners.
0711: */
0712: /* package */void derefPart(LayoutPart part) {
0713: if (part instanceof ViewPane) {
0714: IViewReference ref = ((ViewPane) part).getViewReference();
0715: if (perspective.isFastView(ref)) {
0716: // Special check: if it's a fast view then it's actual ViewStack
0717: // may only contain placeholders and the stack is represented in
0718: // the presentation by a container placeholder...make sure the
0719: // PartPlaceHolder for 'ref' is removed from the ViewStack
0720: String id = perspective.getFastViewManager()
0721: .getIdForRef(ref);
0722: LayoutPart parentPart = findPart(id, null);
0723: if (parentPart instanceof ContainerPlaceholder) {
0724: ViewStack vs = (ViewStack) ((ContainerPlaceholder) parentPart)
0725: .getRealContainer();
0726: LayoutPart[] kids = vs.getChildren();
0727: for (int i = 0; i < kids.length; i++) {
0728: if (kids[i] instanceof PartPlaceholder) {
0729: if (ref.getId().equals(kids[i].id))
0730: vs.remove(kids[i]);
0731: }
0732: }
0733: }
0734: perspective.getFastViewManager().removeViewReference(
0735: ref, true, true);
0736: }
0737: }
0738:
0739: // Get vital part stats before reparenting.
0740: ILayoutContainer oldContainer = part.getContainer();
0741: boolean wasDocked = part.isDocked();
0742: Shell oldShell = part.getShell();
0743:
0744: // Reparent the part back to the main window
0745: part.reparent(mainLayout.getParent());
0746:
0747: // Update container.
0748: if (oldContainer == null) {
0749: return;
0750: }
0751:
0752: oldContainer.remove(part);
0753:
0754: LayoutPart[] children = oldContainer.getChildren();
0755: if (wasDocked) {
0756: boolean hasChildren = (children != null)
0757: && (children.length > 0);
0758: if (hasChildren) {
0759: // make sure one is at least visible
0760: int childVisible = 0;
0761: for (int i = 0; i < children.length; i++) {
0762: if (children[i].getControl() != null) {
0763: childVisible++;
0764: }
0765: }
0766:
0767: // none visible, then reprarent and remove container
0768: if (oldContainer instanceof ViewStack) {
0769: ViewStack folder = (ViewStack) oldContainer;
0770:
0771: // Is the part in the trim?
0772: boolean inTrim = false;
0773: // Safety check...there may be no FastViewManager
0774: if (perspective.getFastViewManager() != null)
0775: inTrim = perspective.getFastViewManager()
0776: .getFastViews(folder.getID()).size() > 0;
0777:
0778: if (childVisible == 0 && !inTrim) {
0779: ILayoutContainer parentContainer = folder
0780: .getContainer();
0781: for (int i = 0; i < children.length; i++) {
0782: folder.remove(children[i]);
0783: parentContainer.add(children[i]);
0784: }
0785: hasChildren = false;
0786: } else if (childVisible == 1) {
0787: LayoutTree layout = mainLayout.getLayoutTree();
0788: layout = layout.find(folder);
0789: layout.setBounds(layout.getBounds());
0790: }
0791: }
0792: }
0793:
0794: if (!hasChildren) {
0795: // There are no more children in this container, so get rid of
0796: // it
0797: if (oldContainer instanceof LayoutPart) {
0798: LayoutPart parent = (LayoutPart) oldContainer;
0799: ILayoutContainer parentContainer = parent
0800: .getContainer();
0801: if (parentContainer != null) {
0802: parentContainer.remove(parent);
0803: parent.dispose();
0804: }
0805: }
0806: }
0807: } else if (!wasDocked) {
0808: if (children == null || children.length == 0) {
0809: // There are no more children in this container, so get rid of
0810: // it
0811: // Turn on redraw again just in case it was off.
0812: //oldShell.setRedraw(true);
0813: DetachedWindow w = (DetachedWindow) oldShell.getData();
0814: oldShell.close();
0815: detachedWindowList.remove(w);
0816: } else {
0817: // There are children. If none are visible hide detached
0818: // window.
0819: boolean allInvisible = true;
0820: for (int i = 0, length = children.length; i < length; i++) {
0821: if (!(children[i] instanceof PartPlaceholder)) {
0822: allInvisible = false;
0823: break;
0824: }
0825: }
0826: if (allInvisible) {
0827: DetachedPlaceHolder placeholder = new DetachedPlaceHolder(
0828: "", //$NON-NLS-1$
0829: oldShell.getBounds());
0830: for (int i = 0, length = children.length; i < length; i++) {
0831: oldContainer.remove(children[i]);
0832: children[i].setContainer(placeholder);
0833: placeholder.add(children[i]);
0834: }
0835: detachedPlaceHolderList.add(placeholder);
0836: DetachedWindow w = (DetachedWindow) oldShell
0837: .getData();
0838: oldShell.close();
0839: detachedWindowList.remove(w);
0840: }
0841: }
0842: }
0843:
0844: }
0845:
0846: /**
0847: * Create a detached window containing a part.
0848: */
0849: private void detach(LayoutPart source, int x, int y) {
0850:
0851: // Detaching is disabled on some platforms ..
0852: if (!detachable) {
0853: return;
0854: }
0855:
0856: LayoutPart part = source.getPart();
0857: // Calculate detached window size.
0858: Point size = part.getSize();
0859: if (size.x == 0 || size.y == 0) {
0860: ILayoutContainer container = part.getContainer();
0861: if (container instanceof LayoutPart) {
0862: size = ((LayoutPart) container).getSize();
0863: }
0864: }
0865: int width = Math.max(size.x, MIN_DETACH_WIDTH);
0866: int height = Math.max(size.y, MIN_DETACH_HEIGHT);
0867:
0868: // Create detached window.
0869: DetachedWindow window = new DetachedWindow(page);
0870: detachedWindowList.add(window);
0871:
0872: // Open window.
0873: window.create();
0874: window.getShell().setBounds(x, y, width, height);
0875: window.open();
0876:
0877: if (part instanceof ViewStack) {
0878: window.getShell().setRedraw(false);
0879: parentWidget.setRedraw(false);
0880: LayoutPart visiblePart = ((ViewStack) part).getSelection();
0881: LayoutPart children[] = ((ViewStack) part).getChildren();
0882: for (int i = 0; i < children.length; i++) {
0883: if (children[i] instanceof ViewPane) {
0884: // remove the part from its current container
0885: derefPart(children[i]);
0886: // add part to detached window.
0887: ViewPane pane = (ViewPane) children[i];
0888: window.add(pane);
0889: }
0890: }
0891: if (visiblePart != null) {
0892: bringPartToTop(visiblePart);
0893: visiblePart.setFocus();
0894: }
0895: window.getShell().setRedraw(true);
0896: parentWidget.setRedraw(true);
0897: } else {
0898: // remove the part from its current container
0899: derefPart(part);
0900: // add part to detached window.
0901: ViewPane pane = (ViewPane) part;
0902: window.add(pane);
0903: part.setFocus();
0904: }
0905:
0906: }
0907:
0908: /**
0909: * Detached a part from the mainLayout. Presently this does not use placeholders
0910: * since the current implementation is not robust enough to remember a view's position
0911: * in more than one root container. For now the view is simply derefed and will dock
0912: * in the default position when attachPart is called.
0913: *
0914: * By default parts detached this way are set to float on top of the workbench
0915: * without docking. It is assumed that people that want to drag a part back onto
0916: * the WorkbenchWindow will detach it via drag and drop.
0917: *
0918: * @param ref
0919: */
0920: public void detachPart(IViewReference ref) {
0921: ViewPane pane = (ViewPane) ((WorkbenchPartReference) ref)
0922: .getPane();
0923: if (canDetach() && pane != null) {
0924: Rectangle bounds = pane.getParentBounds();
0925: detach(pane, bounds.x, bounds.y);
0926: }
0927: }
0928:
0929: /**
0930: * Create a detached window containing a part.
0931: */
0932: public void addDetachedPart(LayoutPart part) {
0933: // Calculate detached window size.
0934: Rectangle bounds = parentWidget.getShell().getBounds();
0935: bounds.x = bounds.x + (bounds.width - 300) / 2;
0936: bounds.y = bounds.y + (bounds.height - 300) / 2;
0937:
0938: addDetachedPart(part, bounds);
0939: }
0940:
0941: public void addDetachedPart(LayoutPart part, Rectangle bounds) {
0942: // Detaching is disabled on some platforms ..
0943: if (!detachable) {
0944: addPart(part);
0945: return;
0946: }
0947:
0948: // Create detached window.
0949: DetachedWindow window = new DetachedWindow(page);
0950: detachedWindowList.add(window);
0951: window.create();
0952:
0953: // add part to detached window.
0954: part.createControl(window.getShell());
0955: ViewPane pane = (ViewPane) part;
0956: window.add(pane);
0957:
0958: // Open window.
0959: window.getShell().setBounds(bounds.x, bounds.y, bounds.width,
0960: bounds.height);
0961: window.open();
0962:
0963: part.setFocus();
0964:
0965: }
0966:
0967: /**
0968: * disableDragging.
0969: */
0970: private void disableAllDrag() {
0971: DragUtil.removeDragTarget(null, dragTarget);
0972: }
0973:
0974: /**
0975: * enableDragging.
0976: */
0977: private void enableAllDrag() {
0978: DragUtil.addDragTarget(null, dragTarget);
0979: }
0980:
0981: /**
0982: * Find the first part with a given ID in the presentation.
0983: * Wild cards now supported.
0984: */
0985: private LayoutPart findPart(String id) {
0986: return findPart(id, null);
0987: }
0988:
0989: /**
0990: * Find the first part that matches the specified
0991: * primary and secondary id pair. Wild cards
0992: * are supported.
0993: */
0994: public LayoutPart findPart(String primaryId, String secondaryId) {
0995: // check main window.
0996: ArrayList matchingParts = new ArrayList();
0997: LayoutPart part = (secondaryId != null) ? findPart(primaryId,
0998: secondaryId, mainLayout.getChildren(), matchingParts)
0999: : findPart(primaryId, mainLayout.getChildren(),
1000: matchingParts);
1001: if (part != null) {
1002: return part;
1003: }
1004:
1005: // check each detached windows.
1006: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
1007: DetachedWindow window = (DetachedWindow) detachedWindowList
1008: .get(i);
1009: part = (secondaryId != null) ? findPart(primaryId,
1010: secondaryId, window.getChildren(), matchingParts)
1011: : findPart(primaryId, window.getChildren(),
1012: matchingParts);
1013: if (part != null) {
1014: return part;
1015: }
1016: }
1017: for (int i = 0; i < detachedPlaceHolderList.size(); i++) {
1018: DetachedPlaceHolder holder = (DetachedPlaceHolder) detachedPlaceHolderList
1019: .get(i);
1020: part = (secondaryId != null) ? findPart(primaryId,
1021: secondaryId, holder.getChildren(), matchingParts)
1022: : findPart(primaryId, holder.getChildren(),
1023: matchingParts);
1024: if (part != null) {
1025: return part;
1026: }
1027: }
1028:
1029: // sort the matching parts
1030: if (matchingParts.size() > 0) {
1031: Collections.sort(matchingParts);
1032: MatchingPart mostSignificantPart = (MatchingPart) matchingParts
1033: .get(0);
1034: if (mostSignificantPart != null) {
1035: return mostSignificantPart.part;
1036: }
1037: }
1038:
1039: // Not found.
1040: return null;
1041: }
1042:
1043: /**
1044: * Find the first part with a given ID in the presentation.
1045: */
1046: private LayoutPart findPart(String id, LayoutPart[] parts,
1047: ArrayList matchingParts) {
1048: for (int i = 0, length = parts.length; i < length; i++) {
1049: LayoutPart part = parts[i];
1050: // check for part equality, parts with secondary ids fail
1051: if (part.getID().equals(id)) {
1052: if (part instanceof ViewPane) {
1053: ViewPane pane = (ViewPane) part;
1054: IViewReference ref = (IViewReference) pane
1055: .getPartReference();
1056: if (ref.getSecondaryId() != null) {
1057: continue;
1058: }
1059: }
1060: return part;
1061: }
1062: // check pattern matching placeholders
1063: else if (part instanceof PartPlaceholder
1064: && ((PartPlaceholder) part).hasWildCard()) {
1065: StringMatcher sm = new StringMatcher(part.getID(),
1066: true, false);
1067: if (sm.match(id)) {
1068: matchingParts.add(new MatchingPart(part.getID(),
1069: null, part));
1070: }
1071: } else if (part instanceof EditorSashContainer) {
1072: // Skip.
1073: } else if (part instanceof ILayoutContainer) {
1074: part = findPart(id, ((ILayoutContainer) part)
1075: .getChildren(), matchingParts);
1076: if (part != null) {
1077: return part;
1078: }
1079: }
1080: }
1081: return null;
1082: }
1083:
1084: /**
1085: * Find the first part that matches the specified
1086: * primary and secondary id pair. Wild cards
1087: * are supported.
1088: */
1089: private LayoutPart findPart(String primaryId, String secondaryId,
1090: LayoutPart[] parts, ArrayList matchingParts) {
1091: for (int i = 0, length = parts.length; i < length; i++) {
1092: LayoutPart part = parts[i];
1093: // check containers first
1094: if (part instanceof ILayoutContainer) {
1095: LayoutPart testPart = findPart(primaryId, secondaryId,
1096: ((ILayoutContainer) part).getChildren(),
1097: matchingParts);
1098: if (testPart != null) {
1099: return testPart;
1100: }
1101: }
1102: // check for view part equality
1103: if (part instanceof ViewPane) {
1104: ViewPane pane = (ViewPane) part;
1105: IViewReference ref = (IViewReference) pane
1106: .getPartReference();
1107: if (ref.getId().equals(primaryId)
1108: && ref.getSecondaryId() != null
1109: && ref.getSecondaryId().equals(secondaryId)) {
1110: return part;
1111: }
1112: }
1113: // check placeholders
1114: else if ((parts[i] instanceof PartPlaceholder)) {
1115: String id = part.getID();
1116:
1117: // optimization: don't bother parsing id if it has no separator -- it can't match
1118: String phSecondaryId = ViewFactory
1119: .extractSecondaryId(id);
1120: if (phSecondaryId == null) {
1121: // but still need to check for wildcard case
1122: if (id.equals(PartPlaceholder.WILD_CARD)) {
1123: matchingParts.add(new MatchingPart(id, null,
1124: part));
1125: }
1126: continue;
1127: }
1128:
1129: String phPrimaryId = ViewFactory.extractPrimaryId(id);
1130: // perfect matching pair
1131: if (phPrimaryId.equals(primaryId)
1132: && phSecondaryId.equals(secondaryId)) {
1133: return part;
1134: }
1135: // check for partial matching pair
1136: StringMatcher sm = new StringMatcher(phPrimaryId, true,
1137: false);
1138: if (sm.match(primaryId)) {
1139: sm = new StringMatcher(phSecondaryId, true, false);
1140: if (sm.match(secondaryId)) {
1141: matchingParts.add(new MatchingPart(phPrimaryId,
1142: phSecondaryId, part));
1143: }
1144: }
1145: } else if (part instanceof EditorSashContainer) {
1146: // Skip.
1147: }
1148: }
1149: return null;
1150: }
1151:
1152: /**
1153: * Returns true if a placeholder exists for a given ID.
1154: */
1155: public boolean hasPlaceholder(String id) {
1156: return hasPlaceholder(id, null);
1157: }
1158:
1159: /**
1160: * Returns true if a placeholder exists for a given ID.
1161: * @since 3.0
1162: */
1163: public boolean hasPlaceholder(String primaryId, String secondaryId) {
1164: LayoutPart testPart;
1165: if (secondaryId == null) {
1166: testPart = findPart(primaryId);
1167: } else {
1168: testPart = findPart(primaryId, secondaryId);
1169: }
1170: return (testPart != null && testPart instanceof PartPlaceholder);
1171: }
1172:
1173: /**
1174: * Returns the layout container.
1175: */
1176: public ViewSashContainer getLayout() {
1177: return mainLayout;
1178: }
1179:
1180: /**
1181: * Gets the active state.
1182: */
1183: public boolean isActive() {
1184: return active;
1185: }
1186:
1187: /**
1188: * Returns whether the presentation is zoomed.
1189: *
1190: * <strong>NOTE:</strong> As of 3.3 this method should always return 'false'
1191: * when using the new min/max behavior. It is only used for
1192: * legacy 'zoom' handling.
1193: */
1194: public boolean isZoomed() {
1195: return mainLayout.getZoomedPart() != null;
1196: }
1197:
1198: /**
1199: * @return The currently maxmized stack (if any)
1200: */
1201: public PartStack getMaximizedStack() {
1202: return maximizedStack;
1203: }
1204:
1205: /**
1206: * Sets the currently maximized stack. Used for query
1207: * and 'unZoom' purposes in the 3.3 presentation.
1208: *
1209: * @param stack The newly maximized stack
1210: */
1211: public void setMaximizedStack(PartStack stack) {
1212: if (stack == maximizedStack)
1213: return;
1214:
1215: maximizedStack = stack;
1216: }
1217:
1218: /**
1219: * Returns the ratio that should be used when docking the given source
1220: * part onto the given target
1221: *
1222: * @param source newly added part
1223: * @param target existing part being dragged over
1224: * @return the final size of the source part (wrt the current size of target)
1225: * after it is docked
1226: */
1227: public static float getDockingRatio(LayoutPart source,
1228: LayoutPart target) {
1229: if ((source instanceof ViewPane || source instanceof ViewStack)
1230: && target instanceof EditorSashContainer) {
1231: return 0.25f;
1232: }
1233: return 0.5f;
1234: }
1235:
1236: /**
1237: * Returns whether changes to a part will affect zoom. There are a few
1238: * conditions for this .. - we are zoomed. - the part is contained in the
1239: * main window. - the part is not the zoom part - the part is not a fast
1240: * view - the part and the zoom part are not in the same editor workbook
1241: * - the part and the zoom part are not in the same view stack.
1242: */
1243: public boolean partChangeAffectsZoom(LayoutPart pane) {
1244: return pane.isObscuredByZoom();
1245: }
1246:
1247: /**
1248: * Remove all references to a part.
1249: */
1250: public void removePart(LayoutPart part) {
1251:
1252: // Reparent the part back to the main window
1253: Composite parent = mainLayout.getParent();
1254: part.reparent(parent);
1255:
1256: // Replace part with a placeholder
1257: ILayoutContainer container = part.getContainer();
1258: if (container != null) {
1259: String placeHolderId = part.getPlaceHolderId();
1260: container.replace(part, new PartPlaceholder(placeHolderId));
1261:
1262: // If the parent is root we're done. Do not try to replace
1263: // it with placeholder.
1264: if (container == mainLayout) {
1265: return;
1266: }
1267:
1268: // If the parent is empty replace it with a placeholder.
1269: LayoutPart[] children = container.getChildren();
1270: if (children != null) {
1271: boolean allInvisible = true;
1272: for (int i = 0, length = children.length; i < length; i++) {
1273: if (!(children[i] instanceof PartPlaceholder)) {
1274: allInvisible = false;
1275: break;
1276: }
1277: }
1278: if (allInvisible && (container instanceof LayoutPart)) {
1279: // what type of window are we in?
1280: LayoutPart cPart = (LayoutPart) container;
1281: //Window oldWindow = cPart.getWindow();
1282: boolean wasDocked = cPart.isDocked();
1283: Shell oldShell = cPart.getShell();
1284: if (wasDocked) {
1285:
1286: // PR 1GDFVBY: ViewStack not disposed when page
1287: // closed.
1288: if (container instanceof ViewStack) {
1289: ((ViewStack) container).dispose();
1290: }
1291:
1292: // replace the real container with a
1293: // ContainerPlaceholder
1294: ILayoutContainer parentContainer = cPart
1295: .getContainer();
1296: ContainerPlaceholder placeholder = new ContainerPlaceholder(
1297: cPart.getID());
1298: placeholder.setRealContainer(container);
1299: parentContainer.replace(cPart, placeholder);
1300:
1301: } else {
1302: DetachedPlaceHolder placeholder = new DetachedPlaceHolder(
1303: "", oldShell.getBounds()); //$NON-NLS-1$
1304: for (int i = 0, length = children.length; i < length; i++) {
1305: children[i].getContainer().remove(
1306: children[i]);
1307: children[i].setContainer(placeholder);
1308: placeholder.add(children[i]);
1309: }
1310: detachedPlaceHolderList.add(placeholder);
1311: DetachedWindow w = (DetachedWindow) oldShell
1312: .getData();
1313: oldShell.close();
1314: detachedWindowList.remove(w);
1315: }
1316: }
1317: }
1318: }
1319: }
1320:
1321: /**
1322: * Add a part to the presentation.
1323: *
1324: * Note: unlike all other LayoutParts, PartPlaceholders will still point to
1325: * their parent container even when it is inactive. This method relies on this
1326: * fact to locate the parent.
1327: */
1328: public void replacePlaceholderWithPart(LayoutPart part) {
1329:
1330: // Look for a PartPlaceholder that will tell us how to position this
1331: // object
1332: PartPlaceholder[] placeholders = collectPlaceholders();
1333: for (int i = 0, length = placeholders.length; i < length; i++) {
1334: if (placeholders[i].getCompoundId().equals(
1335: part.getCompoundId())) {
1336: // found a matching placeholder which we can replace with the
1337: // new View
1338: ILayoutContainer container = placeholders[i]
1339: .getContainer();
1340: if (container != null) {
1341: if (container instanceof ContainerPlaceholder) {
1342: // One of the children is now visible so replace the
1343: // ContainerPlaceholder with the real container
1344: ContainerPlaceholder containerPlaceholder = (ContainerPlaceholder) container;
1345: ILayoutContainer parentContainer = containerPlaceholder
1346: .getContainer();
1347: container = (ILayoutContainer) containerPlaceholder
1348: .getRealContainer();
1349: if (container instanceof LayoutPart) {
1350: parentContainer.replace(
1351: containerPlaceholder,
1352: (LayoutPart) container);
1353: }
1354: containerPlaceholder.setRealContainer(null);
1355: }
1356: container.replace(placeholders[i], part);
1357: return;
1358: }
1359: }
1360: }
1361:
1362: }
1363:
1364: /**
1365: * @see org.eclipse.ui.IPersistable
1366: */
1367: public IStatus restoreState(IMemento memento) {
1368: // Restore main window.
1369: IMemento childMem = memento
1370: .getChild(IWorkbenchConstants.TAG_MAIN_WINDOW);
1371: IStatus r = mainLayout.restoreState(childMem);
1372:
1373: // Restore each floating window.
1374: if (detachable) {
1375: IMemento detachedWindows[] = memento
1376: .getChildren(IWorkbenchConstants.TAG_DETACHED_WINDOW);
1377: for (int nX = 0; nX < detachedWindows.length; nX++) {
1378: DetachedWindow win = new DetachedWindow(page);
1379: detachedWindowList.add(win);
1380: win.restoreState(detachedWindows[nX]);
1381: }
1382: IMemento childrenMem[] = memento
1383: .getChildren(IWorkbenchConstants.TAG_HIDDEN_WINDOW);
1384: for (int i = 0, length = childrenMem.length; i < length; i++) {
1385: DetachedPlaceHolder holder = new DetachedPlaceHolder(
1386: "", new Rectangle(0, 0, 0, 0)); //$NON-NLS-1$
1387: holder.restoreState(childrenMem[i]);
1388: detachedPlaceHolderList.add(holder);
1389: }
1390: }
1391:
1392: // Get the cached id of the currently maximized stack
1393: maximizedStackId = childMem
1394: .getString(IWorkbenchConstants.TAG_MAXIMIZED);
1395:
1396: return r;
1397: }
1398:
1399: /**
1400: * @see org.eclipse.ui.IPersistable
1401: */
1402: public IStatus saveState(IMemento memento) {
1403: // Persist main window.
1404: IMemento childMem = memento
1405: .createChild(IWorkbenchConstants.TAG_MAIN_WINDOW);
1406: IStatus r = mainLayout.saveState(childMem);
1407:
1408: if (detachable) {
1409: // Persist each detached window.
1410: for (int i = 0, length = detachedWindowList.size(); i < length; i++) {
1411: DetachedWindow window = (DetachedWindow) detachedWindowList
1412: .get(i);
1413: childMem = memento
1414: .createChild(IWorkbenchConstants.TAG_DETACHED_WINDOW);
1415: window.saveState(childMem);
1416: }
1417: for (int i = 0, length = detachedPlaceHolderList.size(); i < length; i++) {
1418: DetachedPlaceHolder holder = (DetachedPlaceHolder) detachedPlaceHolderList
1419: .get(i);
1420: childMem = memento
1421: .createChild(IWorkbenchConstants.TAG_HIDDEN_WINDOW);
1422: holder.saveState(childMem);
1423: }
1424: }
1425:
1426: // Write out the id of the maximized (View) stack (if any)
1427: // NOTE: we only write this out if it's a ViewStack since the
1428: // Editor Area is handled by the perspective
1429: if (maximizedStack instanceof ViewStack) {
1430: childMem.putString(IWorkbenchConstants.TAG_MAXIMIZED,
1431: maximizedStack.getID());
1432: } else if (maximizedStackId != null) {
1433: // Maintain the cache if the perspective has never been activated
1434: childMem.putString(IWorkbenchConstants.TAG_MAXIMIZED,
1435: maximizedStackId);
1436: }
1437:
1438: return r;
1439: }
1440:
1441: /**
1442: * Zoom in on a particular layout part.
1443: */
1444: public void zoomIn(IWorkbenchPartReference ref) {
1445: PartPane pane = ((WorkbenchPartReference) ref).getPane();
1446:
1447: parentWidget.setRedraw(false);
1448: try {
1449: pane.requestZoomIn();
1450: } finally {
1451: parentWidget.setRedraw(true);
1452: }
1453: }
1454:
1455: /**
1456: * Zoom out.
1457: */
1458: public void zoomOut() {
1459: // New 3.3 behavior
1460: if (Perspective.useNewMinMax(perspective)) {
1461: if (maximizedStack != null)
1462: maximizedStack
1463: .setState(IStackPresentationSite.STATE_RESTORED);
1464: return;
1465: }
1466:
1467: LayoutPart zoomPart = mainLayout.getZoomedPart();
1468: if (zoomPart != null) {
1469: zoomPart.requestZoomOut();
1470: }
1471: }
1472:
1473: /**
1474: * Forces the perspective to have no zoomed or minimized parts.
1475: * This is used when switching to the 3.3 presentation...
1476: */
1477: public void forceNoZoom() {
1478: // Ensure that nobody's zoomed
1479: zoomOut();
1480:
1481: // Now, walk the layout ensuring that nothing is minimized
1482: LayoutPart[] kids = mainLayout.getChildren();
1483: for (int i = 0; i < kids.length; i++) {
1484: if (kids[i] instanceof ViewStack) {
1485: ((ViewStack) kids[i]).setMinimized(false);
1486: } else if (kids[i] instanceof EditorSashContainer) {
1487: LayoutPart[] editorStacks = ((EditorSashContainer) kids[i])
1488: .getChildren();
1489: for (int j = 0; j < editorStacks.length; j++) {
1490: if (editorStacks[j] instanceof EditorStack) {
1491: ((EditorStack) editorStacks[j])
1492: .setMinimized(false);
1493: }
1494: }
1495: }
1496: }
1497: }
1498:
1499: /**
1500: * Captures the current bounds of all ViewStacks and the editor
1501: * area and puts them into an ID -> Rectangle map. This info is
1502: * used to cache the bounds so that we can correctly place minimized
1503: * stacks during a 'maximized' operation (where the iterative min's
1504: * affect the current layout while being performed.
1505: */
1506: public void updateBoundsMap() {
1507: boundsMap.clear();
1508:
1509: // Walk the layout gathering the current bounds of each stack
1510: // and the editor area
1511: LayoutPart[] kids = mainLayout.getChildren();
1512: for (int i = 0; i < kids.length; i++) {
1513: if (kids[i] instanceof ViewStack) {
1514: ViewStack vs = (ViewStack) kids[i];
1515: boundsMap.put(vs.getID(), vs.getBounds());
1516: } else if (kids[i] instanceof EditorSashContainer) {
1517: EditorSashContainer esc = (EditorSashContainer) kids[i];
1518: boundsMap.put(esc.getID(), esc.getBounds());
1519: }
1520: }
1521: }
1522:
1523: /**
1524: * Resets the bounds map so that it won't interfere with normal minimize
1525: * operayions
1526: */
1527: public void resetBoundsMap() {
1528: boundsMap.clear();
1529: }
1530:
1531: public Rectangle getCachedBoundsFor(String id) {
1532: return (Rectangle) boundsMap.get(id);
1533: }
1534: }
|