001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * Cagatay Kavukcuoglu <cagatayk@acm.org>
011: * - Fix for bug 10025 - Resizing views should not use height ratios
012: *******************************************************************************/package org.eclipse.ui.internal;
013:
014: import org.eclipse.swt.SWT;
015: import org.eclipse.swt.graphics.Point;
016: import org.eclipse.swt.graphics.Rectangle;
017: import org.eclipse.swt.widgets.Composite;
018: import org.eclipse.swt.widgets.Control;
019: import org.eclipse.swt.widgets.Shell;
020: import org.eclipse.ui.ISizeProvider;
021: import org.eclipse.ui.IWorkbenchWindow;
022: import org.eclipse.ui.internal.dnd.IDropTarget;
023: import org.eclipse.ui.internal.dnd.SwtUtil;
024:
025: /**
026: * A presentation part is used to build the presentation for the
027: * workbench. Common subclasses are pane and folder.
028: */
029: abstract public class LayoutPart implements ISizeProvider {
030: protected ILayoutContainer container;
031:
032: protected String id;
033:
034: public static final String PROP_VISIBILITY = "PROP_VISIBILITY"; //$NON-NLS-1$
035:
036: /**
037: * Number of times deferUpdates(true) has been called without a corresponding
038: * deferUpdates(false)
039: */
040: private int deferCount = 0;
041:
042: /**
043: * PresentationPart constructor comment.
044: */
045: public LayoutPart(String id) {
046: super ();
047: this .id = id;
048: }
049:
050: /**
051: * When a layout part closes, focus will return to a previously active part.
052: * This method determines whether this part should be considered for activation
053: * when another part closes. If a group of parts are all closing at the same time,
054: * they will all return false from this method while closing to ensure that the
055: * parent does not activate a part that is in the process of closing. Parts will
056: * also return false from this method if they are minimized, closed fast views,
057: * obscured by zoom, etc.
058: *
059: * @return true iff the parts in this container may be given focus when the active
060: * part is closed
061: */
062: public boolean allowsAutoFocus() {
063: if (container != null) {
064: return container.allowsAutoFocus();
065: }
066: return true;
067: }
068:
069: /**
070: * Creates the SWT control
071: */
072: abstract public void createControl(Composite parent);
073:
074: /**
075: * Disposes the SWT control
076: */
077: public void dispose() {
078: }
079:
080: /**
081: * Gets the presentation bounds.
082: */
083: public Rectangle getBounds() {
084: return new Rectangle(0, 0, 0, 0);
085: }
086:
087: /**
088: * Gets the parent for this part.
089: * <p>
090: * In general, this is non-null if the object has been added to a container and the
091: * container's widgetry exists. The exception to this rule is PartPlaceholders
092: * created when restoring a ViewStack using restoreState, which point to the
093: * ViewStack even if its widgetry doesn't exist yet. Returns null in the remaining
094: * cases.
095: * </p>
096: * <p>
097: * TODO: change the semantics of this method to always point to the parent container,
098: * regardless of whether its widgetry exists. Locate and refactor code that is currently
099: * depending on the special cases.
100: * </p>
101: */
102: public ILayoutContainer getContainer() {
103: return container;
104: }
105:
106: /**
107: * Get the part control. This method may return null.
108: */
109: abstract public Control getControl();
110:
111: /**
112: * Gets the ID for this part.
113: */
114: public String getID() {
115: return id;
116: }
117:
118: /**
119: * Returns the compound ID for this part.
120: * The compound ID is of the form: primaryId [':' + secondaryId]
121: *
122: * @return the compound ID for this part.
123: */
124: public String getCompoundId() {
125: return getID();
126: }
127:
128: public boolean isCompressible() {
129: return false;
130: }
131:
132: /**
133: * Gets the presentation size.
134: */
135: public Point getSize() {
136: Rectangle r = getBounds();
137: Point ptSize = new Point(r.width, r.height);
138: return ptSize;
139: }
140:
141: /**
142: * @see org.eclipse.ui.presentations.StackPresentation#getSizeFlags(boolean)
143: *
144: * @since 3.1
145: */
146: public int getSizeFlags(boolean horizontal) {
147: return SWT.MIN;
148: }
149:
150: /**
151: * @see org.eclipse.ui.presentations.StackPresentation#computePreferredSize(boolean, int, int, int)
152: *
153: * @since 3.1
154: */
155: public int computePreferredSize(boolean width,
156: int availableParallel, int availablePerpendicular,
157: int preferredParallel) {
158:
159: return preferredParallel;
160: }
161:
162: public IDropTarget getDropTarget(Object draggedObject,
163: Point displayCoordinates) {
164: return null;
165: }
166:
167: public boolean isDocked() {
168: Shell s = getShell();
169: if (s == null) {
170: return false;
171: }
172:
173: return s.getData() instanceof IWorkbenchWindow;
174: }
175:
176: public Shell getShell() {
177: Control ctrl = getControl();
178: if (!SwtUtil.isDisposed(ctrl)) {
179: return ctrl.getShell();
180: }
181: return null;
182: }
183:
184: /**
185: * Returns the workbench window window for a part.
186: *
187: * @return the workbench window, or <code>null</code> if there's no window
188: * associated with this part.
189: */
190: public IWorkbenchWindow getWorkbenchWindow() {
191: Shell s = getShell();
192: if (s == null) {
193: return null;
194: }
195: Object data = s.getData();
196: if (data instanceof IWorkbenchWindow) {
197: return (IWorkbenchWindow) data;
198: } else if (data instanceof DetachedWindow) {
199: return ((DetachedWindow) data).getWorkbenchPage()
200: .getWorkbenchWindow();
201: }
202:
203: return null;
204:
205: }
206:
207: /**
208: * Move the control over another one.
209: */
210: public void moveAbove(Control refControl) {
211: }
212:
213: /**
214: * Reparent a part.
215: */
216: public void reparent(Composite newParent) {
217: Control control = getControl();
218: if ((control == null) || (control.getParent() == newParent)) {
219: return;
220: }
221:
222: if (control.isReparentable()) {
223: // make control small in case it is not resized with other controls
224: //control.setBounds(0, 0, 0, 0);
225: // By setting the control to disabled before moving it,
226: // we ensure that the focus goes away from the control and its children
227: // and moves somewhere else
228: boolean enabled = control.getEnabled();
229: control.setEnabled(false);
230: control.setParent(newParent);
231: control.setEnabled(enabled);
232: control.moveAbove(null);
233: }
234: }
235:
236: /**
237: * Returns true if this part was set visible. This returns whatever was last passed into
238: * setVisible, but does not necessarily indicate that the part can be seen (ie: one of its
239: * ancestors may be invisible)
240: */
241: public boolean getVisible() {
242: Control ctrl = getControl();
243: if (!SwtUtil.isDisposed(ctrl)) {
244: return ctrl.getVisible();
245: }
246: return false;
247: }
248:
249: /**
250: * Returns true if this part can be seen. Returns false if the part or any of its ancestors
251: * are invisible.
252: */
253: public boolean isVisible() {
254: Control ctrl = getControl();
255: if (ctrl != null && !ctrl.isDisposed()) {
256: return ctrl.isVisible();
257: }
258: return false;
259: }
260:
261: /**
262: * Shows the receiver if <code>visible</code> is true otherwise hide it.
263: */
264: public void setVisible(boolean makeVisible) {
265: Control ctrl = getControl();
266: if (!SwtUtil.isDisposed(ctrl)) {
267: if (makeVisible == ctrl.getVisible()) {
268: return;
269: }
270:
271: if (!makeVisible && isFocusAncestor(ctrl)) {
272: // Workaround for Bug 60970 [EditorMgmt] setActive() called on an editor when it does not have focus.
273: // Force focus on the shell so that when ctrl is hidden,
274: // SWT does not try to send focus elsewhere, which may cause
275: // some other part to be activated, which affects the part
276: // activation order and can cause flicker.
277: ctrl.getShell().forceFocus();
278: }
279:
280: ctrl.setVisible(makeVisible);
281: }
282: }
283:
284: /**
285: * Returns <code>true</code> if the given control or any of its descendents has focus.
286: */
287: private boolean isFocusAncestor(Control ctrl) {
288: Control f = ctrl.getDisplay().getFocusControl();
289: while (f != null && f != ctrl) {
290: f = f.getParent();
291: }
292: return f == ctrl;
293: }
294:
295: /**
296: * Sets the presentation bounds.
297: */
298: public void setBounds(Rectangle r) {
299: Control ctrl = getControl();
300: if (!SwtUtil.isDisposed(ctrl)) {
301: ctrl.setBounds(r);
302: }
303: }
304:
305: /**
306: * Sets the parent for this part.
307: */
308: public void setContainer(ILayoutContainer container) {
309:
310: this .container = container;
311:
312: if (container != null) {
313: setZoomed(container.childIsZoomed(this ));
314: }
315: }
316:
317: /**
318: * Sets focus to this part.
319: */
320: public void setFocus() {
321: }
322:
323: /**
324: * Sets the part ID.
325: */
326: public void setID(String str) {
327: id = str;
328: }
329:
330: /* (non-Javadoc)
331: * @see org.eclipse.ui.internal.IWorkbenchDragDropPart#getPart()
332: */
333: public LayoutPart getPart() {
334: return this ;
335: }
336:
337: public void childRequestZoomIn(LayoutPart toZoom) {
338:
339: }
340:
341: public void childRequestZoomOut() {
342:
343: }
344:
345: public final void requestZoomOut() {
346: ILayoutContainer container = getContainer();
347: if (container != null) {
348: container.childRequestZoomOut();
349: }
350: }
351:
352: public final void requestZoomIn() {
353: ILayoutContainer container = getContainer();
354: if (container != null) {
355: container.childRequestZoomIn(this );
356: }
357: }
358:
359: public final boolean isObscuredByZoom() {
360: ILayoutContainer container = getContainer();
361:
362: if (container != null) {
363: return container.childObscuredByZoom(this );
364: }
365:
366: return false;
367: }
368:
369: public boolean childObscuredByZoom(LayoutPart toTest) {
370: return false;
371: }
372:
373: public boolean childIsZoomed(LayoutPart childToTest) {
374: return false;
375: }
376:
377: public void setZoomed(boolean isZoomed) {
378:
379: }
380:
381: /**
382: * deferUpdates(true) disables widget updates until a corresponding call to
383: * deferUpdates(false). Exactly what gets deferred is the decision
384: * of each LayoutPart, however the part may only defer operations in a manner
385: * that does not affect the final result.
386: * That is, the state of the receiver after the final call to deferUpdates(false)
387: * must be exactly the same as it would have been if nothing had been deferred.
388: *
389: * @param shouldDefer true iff events should be deferred
390: */
391: public final void deferUpdates(boolean shouldDefer) {
392: if (shouldDefer) {
393: if (deferCount == 0) {
394: startDeferringEvents();
395: }
396: deferCount++;
397: } else {
398: if (deferCount > 0) {
399: deferCount--;
400: if (deferCount == 0) {
401: handleDeferredEvents();
402: }
403: }
404: }
405: }
406:
407: /**
408: * This is called when deferUpdates(true) causes UI events for this
409: * part to be deferred. Subclasses can overload to initialize any data
410: * structures that they will use to collect deferred events.
411: */
412: protected void startDeferringEvents() {
413:
414: }
415:
416: /**
417: * Immediately processes all UI events which were deferred due to a call to
418: * deferUpdates(true). This is called when the last call is made to
419: * deferUpdates(false). Subclasses should overload this method if they
420: * defer some or all UI processing during deferUpdates.
421: */
422: protected void handleDeferredEvents() {
423:
424: }
425:
426: /**
427: * Subclasses can call this method to determine whether UI updates should
428: * be deferred. Returns true iff there have been any calls to deferUpdates(true)
429: * without a corresponding call to deferUpdates(false). Any operation which is
430: * deferred based on the result of this method should be performed later within
431: * handleDeferredEvents().
432: *
433: * @return true iff updates should be deferred.
434: */
435: protected final boolean isDeferred() {
436: return deferCount > 0;
437: }
438:
439: /**
440: * Writes a description of the layout to the given string buffer.
441: * This is used for drag-drop test suites to determine if two layouts are the
442: * same. Like a hash code, the description should compare as equal iff the
443: * layouts are the same. However, it should be user-readable in order to
444: * help debug failed tests. Although these are english readable strings,
445: * they do not need to be translated.
446: *
447: * @param buf
448: */
449: public void describeLayout(StringBuffer buf) {
450:
451: }
452:
453: /**
454: * Returns an id representing this part, suitable for use in a placeholder.
455: *
456: * @since 3.0
457: */
458: public String getPlaceHolderId() {
459: return getID();
460: }
461:
462: public void resizeChild(LayoutPart childThatChanged) {
463:
464: }
465:
466: public void flushLayout() {
467: ILayoutContainer container = getContainer();
468: if (getContainer() != null) {
469: container.resizeChild(this );
470: }
471: }
472:
473: /**
474: * Returns true iff the given part can be added to this ILayoutContainer
475: * @param toAdd
476: * @return
477: * @since 3.1
478: */
479: public boolean allowsAdd(LayoutPart toAdd) {
480: return false;
481: }
482:
483: /**
484: * Tests the integrity of this object. Throws an exception if the object's state
485: * is not internally consistent. For use in test suites.
486: */
487: public void testInvariants() {
488: }
489: }
|