| /******************************************************************************* |
| * Copyright (c) 2000, 2007 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| * Cagatay Kavukcuoglu <cagatayk@acm.org> |
| * - Fix for bug 10025 - Resizing views should not use height ratios |
| *******************************************************************************/ |
| package org.eclipse.ui.internal; |
| |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.graphics.Point; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.ui.ISizeProvider; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.internal.dnd.IDropTarget; |
| import org.eclipse.ui.internal.dnd.SwtUtil; |
| |
| /** |
| * A presentation part is used to build the presentation for the |
| * workbench. Common subclasses are pane and folder. |
| */ |
| abstract public class LayoutPart implements ISizeProvider { |
| protected ILayoutContainer container; |
| |
| protected String id; |
| |
| public static final String PROP_VISIBILITY = "PROP_VISIBILITY"; //$NON-NLS-1$ |
| |
| /** |
| * Number of times deferUpdates(true) has been called without a corresponding |
| * deferUpdates(false) |
| */ |
| private int deferCount = 0; |
| |
| /** |
| * PresentationPart constructor comment. |
| */ |
| public LayoutPart(String id) { |
| super(); |
| this.id = id; |
| } |
| |
| /** |
| * When a layout part closes, focus will return to a previously active part. |
| * This method determines whether this part should be considered for activation |
| * when another part closes. If a group of parts are all closing at the same time, |
| * they will all return false from this method while closing to ensure that the |
| * parent does not activate a part that is in the process of closing. Parts will |
| * also return false from this method if they are minimized, closed fast views, |
| * obscured by zoom, etc. |
| * |
| * @return true iff the parts in this container may be given focus when the active |
| * part is closed |
| */ |
| public boolean allowsAutoFocus() { |
| if (container != null) { |
| return container.allowsAutoFocus(); |
| } |
| return true; |
| } |
| |
| |
| /** |
| * Creates the SWT control |
| */ |
| abstract public void createControl(Composite parent); |
| |
| /** |
| * Disposes the SWT control |
| */ |
| public void dispose() { |
| } |
| |
| /** |
| * Gets the presentation bounds. |
| */ |
| public Rectangle getBounds() { |
| return new Rectangle(0, 0, 0, 0); |
| } |
| |
| /** |
| * Gets the parent for this part. |
| * <p> |
| * In general, this is non-null if the object has been added to a container and the |
| * container's widgetry exists. The exception to this rule is PartPlaceholders |
| * created when restoring a ViewStack using restoreState, which point to the |
| * ViewStack even if its widgetry doesn't exist yet. Returns null in the remaining |
| * cases. |
| * </p> |
| * <p> |
| * TODO: change the semantics of this method to always point to the parent container, |
| * regardless of whether its widgetry exists. Locate and refactor code that is currently |
| * depending on the special cases. |
| * </p> |
| */ |
| public ILayoutContainer getContainer() { |
| return container; |
| } |
| |
| /** |
| * Get the part control. This method may return null. |
| */ |
| abstract public Control getControl(); |
| |
| /** |
| * Gets the ID for this part. |
| */ |
| public String getID() { |
| return id; |
| } |
| |
| /** |
| * Returns the compound ID for this part. |
| * The compound ID is of the form: primaryId [':' + secondaryId] |
| * |
| * @return the compound ID for this part. |
| */ |
| public String getCompoundId() { |
| return getID(); |
| } |
| |
| public boolean isCompressible() { |
| return false; |
| } |
| |
| /** |
| * Gets the presentation size. |
| */ |
| public Point getSize() { |
| Rectangle r = getBounds(); |
| Point ptSize = new Point(r.width, r.height); |
| return ptSize; |
| } |
| |
| /** |
| * @see org.eclipse.ui.presentations.StackPresentation#getSizeFlags(boolean) |
| * |
| * @since 3.1 |
| */ |
| public int getSizeFlags(boolean horizontal) { |
| return SWT.MIN; |
| } |
| |
| /** |
| * @see org.eclipse.ui.presentations.StackPresentation#computePreferredSize(boolean, int, int, int) |
| * |
| * @since 3.1 |
| */ |
| public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredParallel) { |
| |
| return preferredParallel; |
| } |
| |
| public IDropTarget getDropTarget(Object draggedObject, Point displayCoordinates) { |
| return null; |
| } |
| |
| public boolean isDocked() { |
| Shell s = getShell(); |
| if (s == null) { |
| return false; |
| } |
| |
| return s.getData() instanceof IWorkbenchWindow; |
| } |
| |
| public Shell getShell() { |
| Control ctrl = getControl(); |
| if (!SwtUtil.isDisposed(ctrl)) { |
| return ctrl.getShell(); |
| } |
| return null; |
| } |
| |
| /** |
| * Returns the workbench window window for a part. |
| * |
| * @return the workbench window, or <code>null</code> if there's no window |
| * associated with this part. |
| */ |
| public IWorkbenchWindow getWorkbenchWindow() { |
| Shell s = getShell(); |
| if (s==null) { |
| return null; |
| } |
| Object data = s.getData(); |
| if (data instanceof IWorkbenchWindow) { |
| return (IWorkbenchWindow)data; |
| } else if (data instanceof DetachedWindow) { |
| return ((DetachedWindow) data).getWorkbenchPage() |
| .getWorkbenchWindow(); |
| } |
| |
| return null; |
| |
| } |
| |
| /** |
| * Move the control over another one. |
| */ |
| public void moveAbove(Control refControl) { |
| } |
| |
| /** |
| * Reparent a part. |
| */ |
| public void reparent(Composite newParent) { |
| Control control = getControl(); |
| if ((control == null) || (control.getParent() == newParent)) { |
| return; |
| } |
| |
| if (control.isReparentable()) { |
| // make control small in case it is not resized with other controls |
| //control.setBounds(0, 0, 0, 0); |
| // By setting the control to disabled before moving it, |
| // we ensure that the focus goes away from the control and its children |
| // and moves somewhere else |
| boolean enabled = control.getEnabled(); |
| control.setEnabled(false); |
| control.setParent(newParent); |
| control.setEnabled(enabled); |
| control.moveAbove(null); |
| } |
| } |
| |
| /** |
| * Returns true if this part was set visible. This returns whatever was last passed into |
| * setVisible, but does not necessarily indicate that the part can be seen (ie: one of its |
| * ancestors may be invisible) |
| */ |
| public boolean getVisible() { |
| Control ctrl = getControl(); |
| if (!SwtUtil.isDisposed(ctrl)) { |
| return ctrl.getVisible(); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns true if this part can be seen. Returns false if the part or any of its ancestors |
| * are invisible. |
| */ |
| public boolean isVisible() { |
| Control ctrl = getControl(); |
| if (ctrl != null && !ctrl.isDisposed()) { |
| return ctrl.isVisible(); |
| } |
| return false; |
| } |
| |
| /** |
| * Shows the receiver if <code>visible</code> is true otherwise hide it. |
| */ |
| public void setVisible(boolean makeVisible) { |
| Control ctrl = getControl(); |
| if (!SwtUtil.isDisposed(ctrl)) { |
| if (makeVisible == ctrl.getVisible()) { |
| return; |
| } |
| |
| if (!makeVisible && isFocusAncestor(ctrl)) { |
| // Workaround for Bug 60970 [EditorMgmt] setActive() called on an editor when it does not have focus. |
| // Force focus on the shell so that when ctrl is hidden, |
| // SWT does not try to send focus elsewhere, which may cause |
| // some other part to be activated, which affects the part |
| // activation order and can cause flicker. |
| ctrl.getShell().forceFocus(); |
| } |
| |
| ctrl.setVisible(makeVisible); |
| } |
| } |
| |
| /** |
| * Returns <code>true</code> if the given control or any of its descendents has focus. |
| */ |
| private boolean isFocusAncestor(Control ctrl) { |
| Control f = ctrl.getDisplay().getFocusControl(); |
| while (f != null && f != ctrl) { |
| f = f.getParent(); |
| } |
| return f == ctrl; |
| } |
| |
| /** |
| * Sets the presentation bounds. |
| */ |
| public void setBounds(Rectangle r) { |
| Control ctrl = getControl(); |
| if (!SwtUtil.isDisposed(ctrl)) { |
| ctrl.setBounds(r); |
| } |
| } |
| |
| /** |
| * Sets the parent for this part. |
| */ |
| public void setContainer(ILayoutContainer container) { |
| |
| this.container = container; |
| |
| if (container != null) { |
| setZoomed(container.childIsZoomed(this)); |
| } |
| } |
| |
| /** |
| * Sets focus to this part. |
| */ |
| public void setFocus() { |
| } |
| |
| /** |
| * Sets the part ID. |
| */ |
| public void setID(String str) { |
| id = str; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ui.internal.IWorkbenchDragDropPart#getPart() |
| */ |
| public LayoutPart getPart() { |
| return this; |
| } |
| |
| public void childRequestZoomIn(LayoutPart toZoom) { |
| |
| } |
| |
| public void childRequestZoomOut() { |
| |
| } |
| |
| public final void requestZoomOut() { |
| ILayoutContainer container = getContainer(); |
| if (container != null) { |
| container.childRequestZoomOut(); |
| } |
| } |
| |
| public final void requestZoomIn() { |
| ILayoutContainer container = getContainer(); |
| if (container != null) { |
| container.childRequestZoomIn(this); |
| } |
| } |
| |
| public final boolean isObscuredByZoom() { |
| ILayoutContainer container = getContainer(); |
| |
| if (container != null) { |
| return container.childObscuredByZoom(this); |
| } |
| |
| return false; |
| } |
| |
| public boolean childObscuredByZoom(LayoutPart toTest) { |
| return false; |
| } |
| |
| public boolean childIsZoomed(LayoutPart childToTest) { |
| return false; |
| } |
| |
| public void setZoomed(boolean isZoomed) { |
| |
| } |
| |
| /** |
| * deferUpdates(true) disables widget updates until a corresponding call to |
| * deferUpdates(false). Exactly what gets deferred is the decision |
| * of each LayoutPart, however the part may only defer operations in a manner |
| * that does not affect the final result. |
| * That is, the state of the receiver after the final call to deferUpdates(false) |
| * must be exactly the same as it would have been if nothing had been deferred. |
| * |
| * @param shouldDefer true iff events should be deferred |
| */ |
| public final void deferUpdates(boolean shouldDefer) { |
| if (shouldDefer) { |
| if (deferCount == 0) { |
| startDeferringEvents(); |
| } |
| deferCount++; |
| } else { |
| if (deferCount > 0) { |
| deferCount--; |
| if (deferCount == 0) { |
| handleDeferredEvents(); |
| } |
| } |
| } |
| } |
| |
| /** |
| * This is called when deferUpdates(true) causes UI events for this |
| * part to be deferred. Subclasses can overload to initialize any data |
| * structures that they will use to collect deferred events. |
| */ |
| protected void startDeferringEvents() { |
| |
| } |
| |
| /** |
| * Immediately processes all UI events which were deferred due to a call to |
| * deferUpdates(true). This is called when the last call is made to |
| * deferUpdates(false). Subclasses should overload this method if they |
| * defer some or all UI processing during deferUpdates. |
| */ |
| protected void handleDeferredEvents() { |
| |
| } |
| |
| /** |
| * Subclasses can call this method to determine whether UI updates should |
| * be deferred. Returns true iff there have been any calls to deferUpdates(true) |
| * without a corresponding call to deferUpdates(false). Any operation which is |
| * deferred based on the result of this method should be performed later within |
| * handleDeferredEvents(). |
| * |
| * @return true iff updates should be deferred. |
| */ |
| protected final boolean isDeferred() { |
| return deferCount > 0; |
| } |
| |
| /** |
| * Writes a description of the layout to the given string buffer. |
| * This is used for drag-drop test suites to determine if two layouts are the |
| * same. Like a hash code, the description should compare as equal iff the |
| * layouts are the same. However, it should be user-readable in order to |
| * help debug failed tests. Although these are english readable strings, |
| * they do not need to be translated. |
| * |
| * @param buf |
| */ |
| public void describeLayout(StringBuffer buf) { |
| |
| } |
| |
| /** |
| * Returns an id representing this part, suitable for use in a placeholder. |
| * |
| * @since 3.0 |
| */ |
| public String getPlaceHolderId() { |
| return getID(); |
| } |
| |
| public void resizeChild(LayoutPart childThatChanged) { |
| |
| } |
| |
| public void flushLayout() { |
| ILayoutContainer container = getContainer(); |
| if (getContainer() != null) { |
| container.resizeChild(this); |
| } |
| } |
| |
| /** |
| * Returns true iff the given part can be added to this ILayoutContainer |
| * @param toAdd |
| * @return |
| * @since 3.1 |
| */ |
| public boolean allowsAdd(LayoutPart toAdd) { |
| return false; |
| } |
| |
| /** |
| * Tests the integrity of this object. Throws an exception if the object's state |
| * is not internally consistent. For use in test suites. |
| */ |
| public void testInvariants() { |
| } |
| } |