diff options
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/carbon/org/eclipse/swt/widgets/Composite.java')
-rw-r--r-- | bundles/org.eclipse.swt/Eclipse SWT/carbon/org/eclipse/swt/widgets/Composite.java | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/carbon/org/eclipse/swt/widgets/Composite.java b/bundles/org.eclipse.swt/Eclipse SWT/carbon/org/eclipse/swt/widgets/Composite.java new file mode 100644 index 0000000000..18f0e3d27f --- /dev/null +++ b/bundles/org.eclipse.swt/Eclipse SWT/carbon/org/eclipse/swt/widgets/Composite.java @@ -0,0 +1,1082 @@ +/******************************************************************************* + * Copyright (c) 2000, 2009 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 + *******************************************************************************/ +package org.eclipse.swt.widgets; + + +import org.eclipse.swt.internal.carbon.OS; + +import org.eclipse.swt.*; +import org.eclipse.swt.graphics.*; + +/** + * Instances of this class are controls which are capable + * of containing other controls. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>NO_BACKGROUND, NO_FOCUS, NO_MERGE_PAINTS, NO_REDRAW_RESIZE, NO_RADIO_GROUP, EMBEDDED, DOUBLE_BUFFERED</dd> + * <dt><b>Events:</b></dt> + * <dd>(none)</dd> + * </dl> + * <p> + * Note: The <code>NO_BACKGROUND</code>, <code>NO_FOCUS</code>, <code>NO_MERGE_PAINTS</code>, + * and <code>NO_REDRAW_RESIZE</code> styles are intended for use with <code>Canvas</code>. + * They can be used with <code>Composite</code> if you are drawing your own, but their + * behavior is undefined if they are used with subclasses of <code>Composite</code> other + * than <code>Canvas</code>. + * </p><p> + * Note: The <code>CENTER</code> style, although undefined for composites, has the + * same value as <code>EMBEDDED</code> which is used to embed widgets from other + * widget toolkits into SWT. On some operating systems (GTK, Motif), this may cause + * the children of this composite to be obscured. + * </p><p> + * This class may be subclassed by custom control implementors + * who are building controls that are constructed from aggregates + * of other controls. + * </p> + * + * @see Canvas + * @see <a href="http://www.eclipse.org/swt/snippets/#composite">Composite snippets</a> + * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> + */ +public class Composite extends Scrollable { + Layout layout; + Control[] tabList; + int scrolledVisibleRgn, siblingsVisibleRgn; + int layoutCount, backgroundMode; + +Composite () { + /* Do nothing */ +} + +/** + * Constructs a new instance of this class given its parent + * and a style value describing its behavior and appearance. + * <p> + * The style value is either one of the style constants defined in + * class <code>SWT</code> which is applicable to instances of this + * class, or must be built by <em>bitwise OR</em>'ing together + * (that is, using the <code>int</code> "|" operator) two or more + * of those <code>SWT</code> style constants. The class description + * lists the style constants that are applicable to the class. + * Style bits are also inherited from superclasses. + * </p> + * + * @param parent a widget which will be the parent of the new instance (cannot be null) + * @param style the style of widget to construct + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> + * </ul> + * + * @see SWT#NO_BACKGROUND + * @see SWT#NO_FOCUS + * @see SWT#NO_MERGE_PAINTS + * @see SWT#NO_REDRAW_RESIZE + * @see SWT#NO_RADIO_GROUP + * @see SWT#EMBEDDED + * @see SWT#DOUBLE_BUFFERED + * @see Widget#getStyle + */ +public Composite (Composite parent, int style) { + super (parent, style); +} + +Control [] _getChildren () { + short [] buffer = new short [1]; + OS.CountSubControls (handle, buffer); + int count = buffer [0]; + Control [] children = new Control [count]; + int i = 0, j = 0; + int child = OS.HIViewGetFirstSubview (handle); + while (i < count) { + if (child != 0) { + Widget widget = display.getWidget (child); + if (widget != null && widget != this) { + if (widget instanceof Control) { + children [j++] = (Control) widget; + } + } + } + child = OS.HIViewGetNextView (child); + i++; + } + if (j == count) return children; + Control [] newChildren = new Control [j]; + System.arraycopy (children, 0, newChildren, 0, j); + return newChildren; +} + +Control [] _getTabList () { + if (tabList == null) return null; + int count = 0; + for (int i=0; i<tabList.length; i++) { + if (!tabList [i].isDisposed ()) count++; + } + if (count == tabList.length) return tabList; + Control [] newList = new Control [count]; + int index = 0; + for (int i=0; i<tabList.length; i++) { + if (!tabList [i].isDisposed ()) { + newList [index++] = tabList [i]; + } + } + tabList = newList; + return tabList; +} + +int callFocusEventHandler (int nextHandler, int theEvent) { + if ((state & CANVAS) != 0) return OS.noErr; + return super.callFocusEventHandler (nextHandler, theEvent); +} + +/** + * Clears any data that has been cached by a Layout for all widgets that + * are in the parent hierarchy of the changed control up to and including the + * receiver. If an ancestor does not have a layout, it is skipped. + * + * @param changed an array of controls that changed state and require a recalculation of size + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> + * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ +public void changed (Control[] changed) { + checkWidget (); + if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT); + for (int i=0; i<changed.length; i++) { + Control control = changed [i]; + if (control == null) error (SWT.ERROR_INVALID_ARGUMENT); + if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + boolean ancestor = false; + Composite composite = control.parent; + while (composite != null) { + ancestor = composite == this; + if (ancestor) break; + composite = composite.parent; + } + if (!ancestor) error (SWT.ERROR_INVALID_PARENT); + } + for (int i=0; i<changed.length; i++) { + Control child = changed [i]; + Composite composite = child.parent; + while (child != this) { + if (composite.layout == null || !composite.layout.flushCache (child)) { + composite.state |= LAYOUT_CHANGED; + } + child = composite; + composite = child.parent; + } + } +} + +public Point computeSize (int wHint, int hHint, boolean changed) { + checkWidget(); + Point size; + if (layout != null) { + if ((wHint == SWT.DEFAULT) || (hHint == SWT.DEFAULT)) { + changed |= (state & LAYOUT_CHANGED) != 0; + size = layout.computeSize (this, wHint, hHint, changed); + state &= ~LAYOUT_CHANGED; + } else { + size = new Point (wHint, hHint); + } + } else { + size = minimumSize (wHint, hHint, changed); + } + if (size.x == 0) size.x = DEFAULT_WIDTH; + if (size.y == 0) size.y = DEFAULT_HEIGHT; + if (wHint != SWT.DEFAULT) size.x = wHint; + if (hHint != SWT.DEFAULT) size.y = hHint; + Rectangle trim = computeTrim (0, 0, size.x, size.y); + return new Point (trim.width, trim.height); +} + +protected void checkSubclass () { + /* Do nothing - Subclassing is allowed */ +} + +Control [] computeTabList () { + Control result [] = super.computeTabList (); + if (result.length == 0) return result; + Control [] list = tabList != null ? _getTabList () : _getChildren (); + for (int i=0; i<list.length; i++) { + Control child = list [i]; + Control [] childList = child.computeTabList (); + if (childList.length != 0) { + Control [] newResult = new Control [result.length + childList.length]; + System.arraycopy (result, 0, newResult, 0, result.length); + System.arraycopy (childList, 0, newResult, result.length, childList.length); + result = newResult; + } + } + return result; +} + +void createHandle () { + state |= CANVAS | GRAB; + boolean scrolled = (style & (SWT.H_SCROLL | SWT.V_SCROLL)) != 0; + if (!scrolled) state |= THEME_BACKGROUND; + if (scrolled || (style & SWT.BORDER) != 0) { + createScrolledHandle (parent.handle); + } else { + createHandle (parent.handle); + } +} + +void createHandle (int parentHandle) { + int features = OS.kControlSupportsEmbedding | OS.kControlSupportsFocus; + int [] outControl = new int [1]; + int window = OS.GetControlOwner (parentHandle); + OS.CreateUserPaneControl (window, null, features, outControl); + if (outControl [0] == 0) error (SWT.ERROR_NO_HANDLES); + handle = outControl [0]; + OS.HIObjectSetAccessibilityIgnored (handle, true); +} + +void createScrolledHandle (int parentHandle) { + int features = OS.kControlSupportsEmbedding; + int [] outControl = new int [1]; + int window = OS.GetControlOwner (parentHandle); + OS.CreateUserPaneControl (window, null, features, outControl); + if (outControl [0] == 0) error (SWT.ERROR_NO_HANDLES); + scrolledHandle = outControl [0]; + outControl [0] = 0; + features |= OS.kControlSupportsFocus; + OS.CreateUserPaneControl (window, null, features, outControl); + if (outControl [0] == 0) error (SWT.ERROR_NO_HANDLES); + handle = outControl [0]; + OS.HIObjectSetAccessibilityIgnored (scrolledHandle, true); + OS.HIObjectSetAccessibilityIgnored (handle, true); +} + +void drawBackground (int control, int context) { + if (control == scrolledHandle) { + Composite parent = this; + Shell shell = getShell (); + if (shell != this) parent = this.parent; + boolean drawBackground = (style & SWT.TRANSPARENT) == 0; + if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) { + parent.drawFocus (control, context, hasFocus () && drawFocusRing (), hasBorder (), drawBackground, inset ()); + } else { + if (hasBorder ()) { + parent.drawFocus (control, context, false, hasBorder (), drawBackground, inset ()); + } else { + parent.fillBackground (control, context, null); + } + } + } else { + if ((state & CANVAS) != 0) { + if ((style & (SWT.NO_BACKGROUND | SWT.TRANSPARENT)) == 0) { + fillBackground (control, context, null); + } + } + } +} + +void enableWidget (boolean enabled) { + //NOT DONE - take into account current scroll bar state + if ((state & CANVAS) != 0) { + if (horizontalBar != null) horizontalBar.enableWidget (enabled); + if (verticalBar != null) verticalBar.enableWidget (enabled); + return; + } + super.enableWidget (enabled); +} + +Composite findDeferredControl () { + return layoutCount > 0 ? this : parent.findDeferredControl (); +} + +Menu [] findMenus (Control control) { + if (control == this) return new Menu [0]; + Menu result [] = super.findMenus (control); + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + Menu [] menuList = child.findMenus (control); + if (menuList.length != 0) { + Menu [] newResult = new Menu [result.length + menuList.length]; + System.arraycopy (result, 0, newResult, 0, result.length); + System.arraycopy (menuList, 0, newResult, result.length, menuList.length); + result = newResult; + } + } + return result; +} + +void fixChildren (Shell newShell, Shell oldShell, Decorations newDecorations, Decorations oldDecorations, Menu [] menus) { + super.fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + children [i].fixChildren (newShell, oldShell, newDecorations, oldDecorations, menus); + } +} + +void fixTabList (Control control) { + if (tabList == null) return; + int count = 0; + for (int i=0; i<tabList.length; i++) { + if (tabList [i] == control) count++; + } + if (count == 0) return; + Control [] newList = null; + int length = tabList.length - count; + if (length != 0) { + newList = new Control [length]; + int index = 0; + for (int i=0; i<tabList.length; i++) { + if (tabList [i] != control) { + newList [index++] = tabList [i]; + } + } + } + tabList = newList; +} + +/** + * Returns the receiver's background drawing mode. This + * will be one of the following constants defined in class + * <code>SWT</code>: + * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, + * <code>INHERTIT_FORCE</code>. + * + * @return the background mode + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SWT + * + * @since 3.2 + */ +public int getBackgroundMode () { + checkWidget (); + return backgroundMode; +} + +/** + * Returns a (possibly empty) array containing the receiver's children. + * Children are returned in the order that they are drawn. The topmost + * control appears at the beginning of the array. Subsequent controls + * draw beneath this control and appear later in the array. + * <p> + * Note: This is not the actual structure used by the receiver + * to maintain its list of children, so modifying the array will + * not affect the receiver. + * </p> + * + * @return an array of children + * + * @see Control#moveAbove + * @see Control#moveBelow + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Control [] getChildren () { + checkWidget(); + return _getChildren (); +} + +int getChildrenCount () { + /* + * NOTE: The current implementation will count + * non-registered children. + */ + short [] count = new short [1]; + OS.CountSubControls (handle, count); + return count [0]; +} + +/** + * Returns layout which is associated with the receiver, or + * null if one has not been set. + * + * @return the receiver's layout or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public Layout getLayout () { + checkWidget(); + return layout; +} + +/** + * Returns <code>true</code> if the receiver has deferred + * the performing of layout, and <code>false</code> otherwise. + * + * @return the receiver's deferred layout state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setLayoutDeferred(boolean) + * @see #isLayoutDeferred() + * + * @since 3.1 + */ +public boolean getLayoutDeferred () { + checkWidget (); + return layoutCount > 0 ; +} + +/** + * Gets the (possibly empty) tabbing order for the control. + * + * @return tabList the ordered list of controls representing the tab order + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setTabList + */ +public Control [] getTabList () { + checkWidget (); + Control [] tabList = _getTabList (); + if (tabList == null) { + int count = 0; + Control [] list =_getChildren (); + for (int i=0; i<list.length; i++) { + if (list [i].isTabGroup ()) count++; + } + tabList = new Control [count]; + int index = 0; + for (int i=0; i<list.length; i++) { + if (list [i].isTabGroup ()) { + tabList [index++] = list [i]; + } + } + } + return tabList; +} + +int getVisibleRegion (int control, boolean clipChildren) { + if (!clipChildren && control == handle) { + if (siblingsVisibleRgn == 0) { + siblingsVisibleRgn = OS.NewRgn (); + calculateVisibleRegion (control, siblingsVisibleRgn, clipChildren); + } + int result = OS.NewRgn (); + OS.CopyRgn (siblingsVisibleRgn, result); + return result; + } + if (control == scrolledHandle) { + if (!clipChildren) return super.getVisibleRegion (control, clipChildren); + if (scrolledVisibleRgn == 0) { + scrolledVisibleRgn = OS.NewRgn (); + calculateVisibleRegion (control, scrolledVisibleRgn, clipChildren); + } + int result = OS.NewRgn (); + OS.CopyRgn (scrolledVisibleRgn, result); + return result; + } + return super.getVisibleRegion (control, clipChildren); +} + +int kEventControlClick (int nextHandler, int theEvent, int userData) { + int result = super.kEventControlClick (nextHandler, theEvent, userData); + if (result == OS.noErr) return result; + if ((state & CANVAS) != 0) { + if (!isEnabled ()) return result; + if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) { + int [] theControl = new int [1]; + int window = OS.GetControlOwner (handle); + OS.GetKeyboardFocus (window, theControl); + if (handle != theControl [0]) { + short [] count = new short [1]; + OS.CountSubControls (handle, count); + if (count [0] == 0) { + if (OS.SetKeyboardFocus (window, handle, (short) focusPart ()) == OS.noErr) { + return OS.noErr; + } + } + } + } + } + return result; +} + +int kEventControlGetFocusPart (int nextHandler, int theEvent, int userData) { + if ((state & CANVAS) != 0) return OS.noErr; + return super.kEventControlGetFocusPart (nextHandler, theEvent, userData); +} + +int kEventControlSetFocusPart (int nextHandler, int theEvent, int userData) { + int result = super.kEventControlSetFocusPart (nextHandler, theEvent, userData); + if (result == OS.noErr) { + if ((state & CANVAS) != 0) { + if (scrolledHandle != 0) { + if ((style & SWT.NO_FOCUS) == 0 && hooksKeys ()) { + short [] part = new short [1]; + OS.GetEventParameter (theEvent, OS.kEventParamControlPart, OS.typeControlPartCode, null, 2, null, part); + redrawWidget (scrolledHandle, false); + } + } + } + } + return result; +} + +int kEventMouseDown (int nextHandler, int theEvent, int userData) { + int result = super.kEventMouseDown (nextHandler, theEvent, userData); + if (result == OS.noErr) return result; + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_FOCUS) != 0) { + Shell shell = getShell (); + int bits = SWT.ON_TOP | SWT.NO_FOCUS; + if ((shell.style & bits) == bits) return OS.noErr; + } + } + return result; +} + +int kEventRawKeyPressed (int nextHandler, int theEvent, int userData) { + /* + * For some reason the next event handler for embedded controls + * stops the event chain and does not let the default handler + * process the raw key event into unicode. The fix to send + * the key from kEventRawKeyDown instead. + * + * Note: should the embedded control no longer stop the event + * chain, there will be two key events issued for one key press. + */ + if ((state & CANVAS) != 0 && (style & SWT.EMBEDDED) != 0) { + int [] theControl = new int[1]; + OS.GetKeyboardFocus (OS.GetControlOwner(handle), theControl); + if (theControl[0] != handle) { + if (!sendKeyEvent (SWT.KeyDown, theEvent)) return OS.noErr; + return OS.eventNotHandledErr; + } + } + + /* + * Feature in the Macintosh. For some reason, the default handler + * does not issue kEventTextInputUnicodeForKeyEvent when the user + * types Command+Space. The fix is to look for this case and + * send the key from kEventRawKeyDown instead. + * + * NOTE: This code relies on Command+Space being consumed and + * will deliver two events if this ever changes. + */ + if ((state & CANVAS) != 0) { + int [] keyCode = new int [1]; + OS.GetEventParameter (theEvent, OS.kEventParamKeyCode, OS.typeUInt32, null, keyCode.length * 4, null, keyCode); + if (keyCode [0] == 49 /* Space */) { + int [] modifiers = new int [1]; + OS.GetEventParameter (theEvent, OS.kEventParamKeyModifiers, OS.typeUInt32, null, 4, null, modifiers); + if (modifiers [0] == OS.cmdKey) { + if (!sendKeyEvent (SWT.KeyDown, theEvent)) return OS.noErr; + } + } + } + return OS.eventNotHandledErr; +} + +int kEventUnicodeKeyPressed (int nextHandler, int theEvent, int userData) { + int result = super.kEventUnicodeKeyPressed (nextHandler, theEvent, userData); + if ((state & CANVAS) != 0) { + int [] keyboardEvent = new int [1]; + OS.GetEventParameter (theEvent, OS.kEventParamTextInputSendKeyboardEvent, OS.typeEventRef, null, keyboardEvent.length * 4, null, keyboardEvent); + int [] keyCode = new int [1]; + OS.GetEventParameter (keyboardEvent [0], OS.kEventParamKeyCode, OS.typeUInt32, null, keyCode.length * 4, null, keyCode); + switch (keyCode [0]) { + case 76: /* KP Enter */ + case 36: /* Return */ + /* + * Feature in the Macintosh. The default behaviour when the return key is pressed is + * to select the default button. This is not the expected behaviour for Composite and + * its subclasses. The fix is to avoid calling the default handler. + */ + return OS.noErr; + } + } + return result; +} + +boolean hooksKeys () { + return hooks (SWT.KeyDown) || hooks (SWT.KeyUp); +} + +void invalidateChildrenVisibleRegion (int control) { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + child.resetVisibleRegion (control); + child.invalidateChildrenVisibleRegion (control); + } +} + +/** + * Returns <code>true</code> if the receiver or any ancestor + * up to and including the receiver's nearest ancestor shell + * has deferred the performing of layouts. Otherwise, <code>false</code> + * is returned. + * + * @return the receiver's deferred layout state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #setLayoutDeferred(boolean) + * @see #getLayoutDeferred() + * + * @since 3.1 + */ +public boolean isLayoutDeferred () { + checkWidget (); + return findDeferredControl () != null; +} + +boolean isTabGroup () { + if ((state & CANVAS) != 0) return true; + return super.isTabGroup (); +} + +/** + * If the receiver has a layout, asks the layout to <em>lay out</em> + * (that is, set the size and location of) the receiver's children. + * If the receiver does not have a layout, do nothing. + * <p> + * This is equivalent to calling <code>layout(true)</code>. + * </p> + * <p> + * Note: Layout is different from painting. If a child is + * moved or resized such that an area in the parent is + * exposed, then the parent will paint. If no child is + * affected, the parent will not paint. + * </p> + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void layout () { + checkWidget (); + layout (true); +} + +/** + * If the receiver has a layout, asks the layout to <em>lay out</em> + * (that is, set the size and location of) the receiver's children. + * If the argument is <code>true</code> the layout must not rely + * on any information it has cached about the immediate children. If it + * is <code>false</code> the layout may (potentially) optimize the + * work it is doing by assuming that none of the receiver's + * children has changed state since the last layout. + * If the receiver does not have a layout, do nothing. + * <p> + * If a child is resized as a result of a call to layout, the + * resize event will invoke the layout of the child. The layout + * will cascade down through all child widgets in the receiver's widget + * tree until a child is encountered that does not resize. Note that + * a layout due to a resize will not flush any cached information + * (same as <code>layout(false)</code>). + * </p> + * <p> + * Note: Layout is different from painting. If a child is + * moved or resized such that an area in the parent is + * exposed, then the parent will paint. If no child is + * affected, the parent will not paint. + * </p> + * + * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void layout (boolean changed) { + checkWidget (); + if (layout == null) return; + layout (changed, false); +} + +/** + * If the receiver has a layout, asks the layout to <em>lay out</em> + * (that is, set the size and location of) the receiver's children. + * If the changed argument is <code>true</code> the layout must not rely + * on any information it has cached about its children. If it + * is <code>false</code> the layout may (potentially) optimize the + * work it is doing by assuming that none of the receiver's + * children has changed state since the last layout. + * If the all argument is <code>true</code> the layout will cascade down + * through all child widgets in the receiver's widget tree, regardless of + * whether the child has changed size. The changed argument is applied to + * all layouts. If the all argument is <code>false</code>, the layout will + * <em>not</em> cascade down through all child widgets in the receiver's widget + * tree. However, if a child is resized as a result of a call to layout, the + * resize event will invoke the layout of the child. Note that + * a layout due to a resize will not flush any cached information + * (same as <code>layout(false)</code>). + * </p> + * <p> + * Note: Layout is different from painting. If a child is + * moved or resized such that an area in the parent is + * exposed, then the parent will paint. If no child is + * affected, the parent will not paint. + * </p> + * + * @param changed <code>true</code> if the layout must flush its caches, and <code>false</code> otherwise + * @param all <code>true</code> if all children in the receiver's widget tree should be laid out, and <code>false</code> otherwise + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ +public void layout (boolean changed, boolean all) { + checkWidget (); + if (layout == null && !all) return; + markLayout (changed, all); + updateLayout (all); +} + +/** + * Forces a lay out (that is, sets the size and location) of all widgets that + * are in the parent hierarchy of the changed control up to and including the + * receiver. The layouts in the hierarchy must not rely on any information + * cached about the changed control or any of its ancestors. The layout may + * (potentially) optimize the work it is doing by assuming that none of the + * peers of the changed control have changed state since the last layout. + * If an ancestor does not have a layout, skip it. + * <p> + * Note: Layout is different from painting. If a child is + * moved or resized such that an area in the parent is + * exposed, then the parent will paint. If no child is + * affected, the parent will not paint. + * </p> + * + * @param changed a control that has had a state change which requires a recalculation of its size + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if the changed array is null any of its controls are null or have been disposed</li> + * <li>ERROR_INVALID_PARENT - if any control in changed is not in the widget tree of the receiver</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @since 3.1 + */ +public void layout (Control [] changed) { + checkWidget (); + if (changed == null) error (SWT.ERROR_INVALID_ARGUMENT); + for (int i=0; i<changed.length; i++) { + Control control = changed [i]; + if (control == null) error (SWT.ERROR_INVALID_ARGUMENT); + if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + boolean ancestor = false; + Composite composite = control.parent; + while (composite != null) { + ancestor = composite == this; + if (ancestor) break; + composite = composite.parent; + } + if (!ancestor) error (SWT.ERROR_INVALID_PARENT); + } + int updateCount = 0; + Composite [] update = new Composite [16]; + for (int i=0; i<changed.length; i++) { + Control child = changed [i]; + Composite composite = child.parent; + while (child != this) { + if (composite.layout != null) { + composite.state |= LAYOUT_NEEDED; + if (!composite.layout.flushCache (child)) { + composite.state |= LAYOUT_CHANGED; + } + } + if (updateCount == update.length) { + Composite [] newUpdate = new Composite [update.length + 16]; + System.arraycopy (update, 0, newUpdate, 0, update.length); + update = newUpdate; + } + child = update [updateCount++] = composite; + composite = child.parent; + } + } + for (int i=updateCount-1; i>=0; i--) { + update [i].updateLayout (false); + } +} + +void markLayout (boolean changed, boolean all) { + if (layout != null) { + state |= LAYOUT_NEEDED; + if (changed) state |= LAYOUT_CHANGED; + } + if (all) { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + children [i].markLayout (changed, all); + } + } +} + +Point minimumSize (int wHint, int Hint, boolean changed) { + Control [] children = _getChildren (); + int width = 0, height = 0; + for (int i=0; i<children.length; i++) { + Rectangle rect = children [i].getBounds (); + width = Math.max (width, rect.x + rect.width); + height = Math.max (height, rect.y + rect.height); + } + return new Point (width, height); +} + +void releaseChildren (boolean destroy) { + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child != null && !child.isDisposed ()) { + child.release (false); + } + } + super.releaseChildren (destroy); +} + +void releaseWidget () { + super.releaseWidget (); + if (scrolledVisibleRgn != 0) OS.DisposeRgn (scrolledVisibleRgn); + if (siblingsVisibleRgn != 0) OS.DisposeRgn (siblingsVisibleRgn); + siblingsVisibleRgn = scrolledVisibleRgn = 0; + layout = null; + tabList = null; +} + +void removeControl (Control control) { + fixTabList (control); +} + +void resetVisibleRegion (int control) { + if (scrolledVisibleRgn != 0) { + OS.DisposeRgn (scrolledVisibleRgn); + scrolledVisibleRgn = 0; + } + if (siblingsVisibleRgn != 0) { + OS.DisposeRgn (siblingsVisibleRgn); + siblingsVisibleRgn = 0; + } + super.resetVisibleRegion (control); +} + +/** + * Sets the background drawing mode to the argument which should + * be one of the following constants defined in class <code>SWT</code>: + * <code>INHERIT_NONE</code>, <code>INHERIT_DEFAULT</code>, + * <code>INHERIT_FORCE</code>. + * + * @param mode the new background mode + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see SWT + * + * @since 3.2 + */ +public void setBackgroundMode (int mode) { + checkWidget (); + backgroundMode = mode; + Control [] children = _getChildren (); + for (int i = 0; i < children.length; i++) { + children [i].updateBackgroundMode (); + } +} + +int setBounds (int x, int y, int width, int height, boolean move, boolean resize, boolean events) { + int result = super.setBounds (x, y, width, height, move, resize, events); + if (layout != null && (result & RESIZED) != 0) { + markLayout (false, false); + updateLayout (false); + } + return result; +} + +public boolean setFocus () { + checkWidget (); + Control [] children = _getChildren (); + for (int i= 0; i < children.length; i++) { + if (children [i].setFocus ()) return true; + } + return super.setFocus (); +} + +/** + * Sets the layout which is associated with the receiver to be + * the argument which may be null. + * + * @param layout the receiver's new layout or null + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setLayout (Layout layout) { + checkWidget(); + this.layout = layout; +} + +/** + * If the argument is <code>true</code>, causes subsequent layout + * operations in the receiver or any of its children to be ignored. + * No layout of any kind can occur in the receiver or any of its + * children until the flag is set to false. + * Layout operations that occurred while the flag was + * <code>true</code> are remembered and when the flag is set to + * <code>false</code>, the layout operations are performed in an + * optimized manner. Nested calls to this method are stacked. + * + * @param defer the new defer state + * + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + * + * @see #layout(boolean) + * @see #layout(Control[]) + * + * @since 3.1 + */ +public void setLayoutDeferred (boolean defer) { + if (!defer) { + if (--layoutCount == 0) { + if ((state & LAYOUT_CHILD) != 0 || (state & LAYOUT_NEEDED) != 0) { + updateLayout (true); + } + } + } else { + layoutCount++; + } +} + +boolean setScrollBarVisible (ScrollBar bar, boolean visible) { + boolean changed = super.setScrollBarVisible (bar, visible); + if (changed && layout != null) { + markLayout (false, false); + updateLayout (false); + } + return changed; +} + +boolean setTabGroupFocus () { + if (isTabItem ()) return setTabItemFocus (); + boolean takeFocus = (style & SWT.NO_FOCUS) == 0; + if ((state & CANVAS) != 0) takeFocus = hooksKeys (); + if (takeFocus && setTabItemFocus ()) return true; + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + Control child = children [i]; + if (child.isTabItem () && child.setTabItemFocus ()) return true; + } + return false; +} + +/** + * Sets the tabbing order for the specified controls to + * match the order that they occur in the argument list. + * + * @param tabList the ordered list of controls representing the tab order or null + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_INVALID_ARGUMENT - if a widget in the tabList is null or has been disposed</li> + * <li>ERROR_INVALID_PARENT - if widget in the tabList is not in the same widget tree</li> + * </ul> + * @exception SWTException <ul> + * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> + * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> + * </ul> + */ +public void setTabList (Control [] tabList) { + checkWidget (); + if (tabList != null) { + for (int i=0; i<tabList.length; i++) { + Control control = tabList [i]; + if (control == null) error (SWT.ERROR_INVALID_ARGUMENT); + if (control.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); + if (control.parent != this) error (SWT.ERROR_INVALID_PARENT); + } + Control [] newList = new Control [tabList.length]; + System.arraycopy (tabList, 0, newList, 0, tabList.length); + tabList = newList; + } + this.tabList = tabList; +} + +int traversalCode (int key, int theEvent) { + if ((state & CANVAS) != 0) { + if ((style & SWT.NO_FOCUS) != 0) return 0; + if (hooksKeys ()) return 0; + } + return super.traversalCode (key, theEvent); +} + +void updateBackgroundMode () { + super.updateBackgroundMode (); + Control [] children = _getChildren (); + for (int i = 0; i < children.length; i++) { + children [i].updateBackgroundMode (); + } +} + +void updateLayout (boolean all) { + Composite parent = findDeferredControl (); + if (parent != null) { + parent.state |= LAYOUT_CHILD; + return; + } + if ((state & LAYOUT_NEEDED) != 0) { + boolean changed = (state & LAYOUT_CHANGED) != 0; + state &= ~(LAYOUT_NEEDED | LAYOUT_CHANGED); + layout.layout (this, changed); + } + if (all) { + state &= ~LAYOUT_CHILD; + Control [] children = _getChildren (); + for (int i=0; i<children.length; i++) { + children [i].updateLayout (all); + } + } +} + +} |