/******************************************************************************* * 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() { } }