Java tutorial
/******************************************************************************* * Copyright (c) 2002, 2015 Innoopract Informationssysteme GmbH 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: * Innoopract Informationssysteme GmbH - initial API and implementation * EclipseSource - ongoing development * Rdiger Herrmann - bug 335112 ******************************************************************************/ package org.eclipse.swt.widgets; import org.eclipse.rap.rwt.internal.lifecycle.ProcessActionRunner; import org.eclipse.rap.rwt.internal.lifecycle.WidgetLCA; import org.eclipse.rap.rwt.internal.theme.CssBoxDimensions; import org.eclipse.rap.rwt.internal.theme.ThemeAdapter; import org.eclipse.rap.rwt.theme.BoxDimensions; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.events.ShellListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.internal.widgets.IDisplayAdapter; import org.eclipse.swt.internal.widgets.IShellAdapter; import org.eclipse.swt.internal.widgets.MenuHolder; import org.eclipse.swt.internal.widgets.shellkit.ShellLCA; import org.eclipse.swt.internal.widgets.shellkit.ShellThemeAdapter; /** * Instances of this class represent the "windows" * which the desktop or "window manager" is managing. * Instances that do not have a parent (that is, they * are built using the constructor, which takes a * <code>Display</code> as the argument) are described * as <em>top level</em> shells. Instances that do have * a parent are described as <em>secondary</em> or * <em>dialog</em> shells. * <p> * Instances are always displayed in one of the maximized, * minimized or normal states: * <ul> * <li> * When an instance is marked as <em>maximized</em>, the * window manager will typically resize it to fill the * entire visible area of the display, and the instance * is usually put in a state where it can not be resized * (even if it has style <code>RESIZE</code>) until it is * no longer maximized. * </li><li> * When an instance is in the <em>normal</em> state (neither * maximized or minimized), its appearance is controlled by * the style constants which were specified when it was created * and the restrictions of the window manager (see below). * </li><li> * When an instance has been marked as <em>minimized</em>, * its contents (client area) will usually not be visible, * and depending on the window manager, it may be * "iconified" (that is, replaced on the desktop by a small * simplified representation of itself), relocated to a * distinguished area of the screen, or hidden. Combinations * of these changes are also possible. * </li> * </ul> * </p><p> * The <em>modality</em> of an instance may be specified using * style bits. The modality style bits are used to determine * whether input is blocked for other shells on the display. * The <code>PRIMARY_MODAL</code> style allows an instance to block * input to its parent. The <code>APPLICATION_MODAL</code> style * allows an instance to block input to every other shell in the * display. The <code>SYSTEM_MODAL</code> style allows an instance * to block input to all shells, including shells belonging to * different applications. * </p><p> * Note: The styles supported by this class are treated * as <em>HINT</em>s, since the window manager for the * desktop on which the instance is visible has ultimate * control over the appearance and behavior of decorations * and modality. For example, some window managers only * support resizable windows and will always assume the * RESIZE style, even if it is not set. In addition, if a * modality style is not supported, it is "upgraded" to a * more restrictive modality style that is supported. For * example, if <code>PRIMARY_MODAL</code> is not supported, * it would be upgraded to <code>APPLICATION_MODAL</code>. * A modality style may also be "downgraded" to a less * restrictive style. For example, most operating systems * no longer support <code>SYSTEM_MODAL</code> because * it can freeze up the desktop, so this is typically * downgraded to <code>APPLICATION_MODAL</code>. * <dl> * <dt><b>Styles:</b></dt> * <dd>BORDER, CLOSE, MIN, MAX, NO_TRIM, RESIZE, TITLE, ON_TOP, TOOL, SHEET</dd> * <dd>APPLICATION_MODAL, MODELESS, PRIMARY_MODAL, SYSTEM_MODAL</dd> * <dt><b>Events:</b></dt> * <dd>Activate, Close, Deactivate, Deiconify, Iconify</dd> * </dl> * Class <code>SWT</code> provides two "convenience constants" * for the most commonly required style combinations: * <dl> * <dt><code>SHELL_TRIM</code></dt> * <dd> * the result of combining the constants which are required * to produce a typical application top level shell: (that * is, <code>CLOSE | TITLE | MIN | MAX | RESIZE</code>) * </dd> * <dt><code>DIALOG_TRIM</code></dt> * <dd> * the result of combining the constants which are required * to produce a typical application dialog shell: (that * is, <code>TITLE | CLOSE | BORDER</code>) * </dd> * </dl> * </p> * <p> * Note: Only one of the styles APPLICATION_MODAL, MODELESS, * PRIMARY_MODAL and SYSTEM_MODAL may be specified. * </p><p> * IMPORTANT: This class is not intended to be subclassed. * </p> * * @see SWT */ public class Shell extends Decorations { private static final BoxDimensions ZERO = new BoxDimensions(0, 0, 0, 0); private static final int MODE_NONE = 0; private static final int MODE_MAXIMIZED = 1; private static final int MODE_MINIMIZED = 2; private static final int MODE_FULLSCREEN = 4; private static final int INITIAL_SIZE_PERCENT = 60; private static final int MIN_WIDTH_LIMIT = 30; private class ShellAdapter implements IShellAdapter { @Override public Control getActiveControl() { return lastActive; } @Override public void setActiveControl(Control control) { Shell.this.setActiveControl(control); } @Override public Rectangle getMenuBounds() { return Shell.this.getMenuBounds(); } @Override public int getTopTrim() { return Shell.this.getTopTrim(); } @Override public void setBounds(Rectangle bounds) { Shell.this.setBounds(bounds, false); } @Override public ToolTip[] getToolTips() { return Shell.this.getToolTips(); } } private Control lastActive; private transient IShellAdapter shellAdapter; private int alpha; private Rectangle savedBounds; private int mode; private boolean modified; private int minWidth; private int minHeight; private ToolTip[] toolTips; private Shell(Display display, Shell parent, int style) { super(checkParent(parent)); if (display != null) { this.display = display; } else { this.display = Display.getCurrent(); if (this.display == null) { this.display = Display.getDefault(); } } alpha = 0xFF; mode = MODE_NONE; this.style = checkStyle(style); addState(HIDDEN); minWidth = MIN_WIDTH_LIMIT; minHeight = getMinHeightLimit(); this.display.addShell(this); reskinWidget(); createWidget(); setInitialSize(); } /** * Constructs a new instance of this class. This is equivalent * to calling <code>Shell((Display) null)</code>. * * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> * * @since 1.3 */ public Shell() { this((Display) null); } /** * Constructs a new instance of this class given only the style value * describing its behavior and appearance. This is equivalent to calling * <code>Shell((Display) null, style)</code>. * <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 style the style of control to construct * @exception SWTException * <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the * thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an * allowed subclass</li> * </ul> * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#NO_TRIM * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * <!--@see SWT#MODELESS--> * <!--@see SWT#PRIMARY_MODAL--> * @see SWT#APPLICATION_MODAL * <!--@see SWT#SYSTEM_MODAL--> * @see SWT#SHEET */ public Shell(int style) { this((Display) null, style); } /** * Constructs a new instance of this class given only the display * to create it on. It is created with style <code>SWT.SHELL_TRIM</code>. * <p> * Note: Currently, null can be passed in for the display argument. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. <b>Passing in null as * the display argument is not considered to be good coding style, * and may not be supported in a future release of SWT.</b> * </p> * * @param display the display to create the shell on * * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public Shell(Display display) { this(display, SWT.SHELL_TRIM); } /** * Constructs a new instance of this class given the display * to create it on 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><p> * Note: Currently, null can be passed in for the display argument. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. <b>Passing in null as * the display argument is not considered to be good coding style, * and may not be supported in a future release of SWT.</b> * </p> * * @param display the display to create the shell on * @param style the style of control to construct * * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> * * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#NO_TRIM * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * @see SWT#MODELESS * @see SWT#PRIMARY_MODAL * @see SWT#APPLICATION_MODAL * @see SWT#SYSTEM_MODAL * @see SWT#SHEET */ public Shell(Display display, int style) { this(display, null, style); } /** * Constructs a new instance of this class given only its * parent. It is created with style <code>SWT.DIALOG_TRIM</code>. * <p> * Note: Currently, null can be passed in for the parent. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. <b>Passing in null as * the parent is not considered to be good coding style, * and may not be supported in a future release of SWT.</b> * </p> * * @param parent a shell which will be the parent of the new instance * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> */ public Shell(Shell parent) { this(parent, SWT.DIALOG_TRIM); } /** * 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><p> * Note: Currently, null can be passed in for the parent. * This has the effect of creating the shell on the currently active * display if there is one. If there is no current display, the * shell is created on a "default" display. <b>Passing in null as * the parent is not considered to be good coding style, * and may not be supported in a future release of SWT.</b> * </p> * * @param parent a shell which will be the parent of the new instance * @param style the style of control to construct * * @exception IllegalArgumentException <ul> * <li>ERROR_INVALID_ARGUMENT - if the parent is disposed</li> * </ul> * @exception SWTException <ul> * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> * </ul> * * @see SWT#BORDER * @see SWT#CLOSE * @see SWT#MIN * @see SWT#MAX * @see SWT#RESIZE * @see SWT#TITLE * @see SWT#NO_TRIM * @see SWT#SHELL_TRIM * @see SWT#DIALOG_TRIM * @see SWT#ON_TOP * @see SWT#TOOL * @see SWT#SHEET * <!--@see SWT#MODELESS--> * <!--@see SWT#PRIMARY_MODAL--> * @see SWT#APPLICATION_MODAL * <!--@see SWT#SYSTEM_MODAL--> */ public Shell(Shell parent, int style) { this(parent != null ? parent.display : null, parent, style); } @Override Shell internalGetShell() { return this; } /** * Returns an array containing all shells which are * descendents of the receiver. * <p> * @return the dialog shells * * @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 Shell[] getShells() { checkWidget(); return internalGetShells(); } private Shell[] internalGetShells() { int count = 0; Shell[] shells = display.getShells(); for (int i = 0; i < shells.length; i++) { Control shell = shells[i]; do { shell = shell._getParent(); } while (shell != null && shell != this); if (shell == this) { count++; } } int index = 0; Shell[] result = new Shell[count]; for (int i = 0; i < shells.length; i++) { Control shell = shells[i]; do { shell = shell._getParent(); } while (shell != null && shell != this); if (shell == this) { result[index++] = shells[i]; } } return result; } /** * If the receiver is visible, moves it to the top of the * drawing order for the display on which it was created * (so that all other shells on that display, which are not * the receiver's children will be drawn behind it) and asks * the window manager to make the shell active * * @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 Control#moveAbove * @see Control#setFocus * @see Control#setVisible * @see Display#getActiveShell * @see Decorations#setDefaultButton(Button) * @see Shell#open * @see Shell#setActive */ public void setActive() { checkWidget(); if (isVisible()) { display.setActiveShell(this); } } /** * If the receiver is visible, moves it to the top of the drawing order for * the display on which it was created (so that all other shells on that * display, which are not the receiver's children will be drawn behind it) and * forces the window manager to make the shell active. * * @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 1.2 * @see Control#moveAbove * @see Control#setFocus * @see Control#setVisible * @see Display#getActiveShell * @see Decorations#setDefaultButton(Button) * @see Shell#open * @see Shell#setActive */ public void forceActive() { checkWidget(); setActive(); } ///////////////////// // Shell measurements // TODO [rst] Move to class Decorations, as soon as it exists @Override public Rectangle getClientArea() { checkWidget(); Rectangle bounds = getBounds(); BoxDimensions padding = getPadding(); BoxDimensions titleBarMargin = getTitleBarMargin(); int hTopTrim; hTopTrim = titleBarMargin.top + titleBarMargin.bottom; hTopTrim += getTitleBarHeight(); hTopTrim += getMenuBarHeight(); BoxDimensions border = getBorder(); int padingWidth = padding.left + padding.right; int paddingHeight = padding.top + padding.bottom; int borderWidth = border.left + border.right; int borderHeight = border.top + border.bottom; return new Rectangle(padding.left, hTopTrim + padding.top, bounds.width - padingWidth - borderWidth, bounds.height - hTopTrim - paddingHeight - borderHeight); } // TODO [rst] Move to class Decorations, as soon as it exists @Override public Rectangle computeTrim(int x, int y, int width, int height) { checkWidget(); int hTopTrim = getTopTrim(); BoxDimensions padding = getPadding(); BoxDimensions border = getBorder(); int paddingWidth = padding.left + padding.right; int paddingHeight = padding.top + padding.bottom; int borderWidth = border.left + border.right; int borderHeight = border.top + border.bottom; return new Rectangle(x - padding.left - border.left, y - hTopTrim - padding.top - border.top, width + paddingWidth + borderWidth, height + hTopTrim + paddingHeight + borderHeight); } private void setInitialSize() { int width = display.getBounds().width * INITIAL_SIZE_PERCENT / 100; int height = display.getBounds().height * INITIAL_SIZE_PERCENT / 100; _setBounds(new Rectangle(0, 0, width, height)); } private int getMinHeightLimit() { BoxDimensions border = getBorder(); BoxDimensions titleBarMargin = getTitleBarMargin(); int titleBarHeight = getTitleBarHeight(); return titleBarMargin.top + titleBarMargin.bottom + titleBarHeight + border.top + border.bottom; } private Rectangle getMenuBounds() { Rectangle result = null; if (getMenuBar() == null) { result = new Rectangle(0, 0, 0, 0); } else { Rectangle bounds = getBounds(); int hTop = (style & SWT.TITLE) != 0 ? 1 : 0; hTop += getTitleBarHeight(); BoxDimensions padding = getPadding(); BoxDimensions border = getBorder(); int paddingWidth = padding.left + padding.right; int borderWidth = border.left + border.right; result = new Rectangle(padding.left, hTop + padding.top, bounds.width - paddingWidth - borderWidth, getMenuBarHeight()); } return result; } @Override public int getBorderWidth() { return getFullScreen() ? 0 : super.getBorderWidth(); } @Override BoxDimensions getBorder() { return getFullScreen() ? ZERO : super.getBorder(); } private int getTopTrim() { BoxDimensions titleBarMargin = getTitleBarMargin(); return titleBarMargin.top + titleBarMargin.bottom + getTitleBarHeight() + getMenuBarHeight(); } private int getTitleBarHeight() { int result = 0; if (!getFullScreen()) { result = getThemeAdapter().getTitleBarHeight(this); } return result; } private BoxDimensions getTitleBarMargin() { if (!getFullScreen()) { return getThemeAdapter().getTitleBarMargin(this); } return CssBoxDimensions.ZERO.dimensions; } private int getMenuBarHeight() { return getThemeAdapter().getMenuBarHeight(this); } private ShellThemeAdapter getThemeAdapter() { return (ShellThemeAdapter) getAdapter(ThemeAdapter.class); } @Override Composite findDeferredControl() { return layoutCount > 0 ? this : null; } @Override void updateMode() { mode &= ~MODE_MAXIMIZED; mode &= ~MODE_MINIMIZED; mode &= ~MODE_FULLSCREEN; } ///////////////////// // Adaptable override @Override @SuppressWarnings("unchecked") public <T> T getAdapter(Class<T> adapter) { if (adapter == IShellAdapter.class) { if (shellAdapter == null) { shellAdapter = new ShellAdapter(); } return (T) shellAdapter; } if (adapter == WidgetLCA.class) { return (T) ShellLCA.INSTANCE; } return super.getAdapter(adapter); } ///////////// // Enablement @Override public void setEnabled(boolean enabled) { checkWidget(); if (getEnabled() != enabled) { super.setEnabled(enabled); if (enabled) { if (!restoreFocus()) { traverseGroup(true); } } } } @Override public boolean isEnabled() { checkWidget(); return getEnabled(); } ///////////// // Visibility @Override public boolean isVisible() { checkWidget(); return getVisible(); } @Override public void setVisible(boolean visible) { checkWidget(); boolean wasVisible = getVisible(); super.setVisible(visible); // Emulate OS behavior: in SWT, a layout is triggered during // Shell#setVisible(true) if (visible && !wasVisible && !isDisposed()) { changed(getChildren()); layout(true, true); } } /** * Moves the receiver to the top of the drawing order for * the display on which it was created (so that all other * shells on that display, which are not the receiver's * children will be drawn behind it), marks it visible, * sets the focus and asks the window manager to make the * shell active. * * @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 Control#moveAbove * @see Control#setFocus * @see Control#setVisible * @see Display#getActiveShell * @see Decorations#setDefaultButton(Button) * @see Shell#setActive * @see Shell#forceActive */ public void open() { checkWidget(); // Order of setActiveShell/bringToTop/setVisible is crucial display.setActiveShell(this); bringToTop(); setVisible(true); if (!restoreFocus() && !traverseGroup(true)) { setFocus(); } } /** * Requests that the window manager close the receiver in * the same way it would be closed when the user clicks on * the "close box" or performs some other platform specific * key or mouse combination that indicates the window * should be removed. * * @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#Close * @see Shell#dispose() */ public void close() { checkWidget(); ProcessActionRunner.add(new Runnable() { @Override public void run() { Event event = new Event(); notifyListeners(SWT.Close, event); if (event.doit) { Shell.this.dispose(); } } }); } /** * Sets the receiver's alpha value. * <p> * This operation <!-- requires the operating system's advanced * widgets subsystem which --> may not be available on some * platforms. * </p> * @param alpha the alpha value * * @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 1.1 */ public void setAlpha(int alpha) { checkWidget(); this.alpha = alpha & 0xFF; } /** * Returns the receiver's alpha value. * * @return the alpha value * * @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 1.1 */ public int getAlpha() { checkWidget(); return alpha; } /** * Sets the receiver's modified state as specified by the argument. * * @param modified the new modified state for the receiver * * </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 1.3 */ public void setModified(boolean modified) { checkWidget(); this.modified = modified; } /** * Gets the receiver's modified state. * * </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 1.3 */ public boolean getModified() { checkWidget(); return modified; } /** * Sets the receiver's minimum size to the size specified by the arguments. * If the new minimum size is larger than the current size of the receiver, * the receiver is resized to the new minimum size. * * @param width the new minimum width for the receiver * @param height the new minimum height for the receiver * * @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 1.3 */ public void setMinimumSize(int width, int height) { checkWidget(); minWidth = Math.max(MIN_WIDTH_LIMIT, width); minHeight = Math.max(getMinHeightLimit(), height); Point size = getSize(); int newWidth = Math.max(size.x, minWidth); int newHeight = Math.max(size.y, minHeight); if (newWidth != size.x || newHeight != size.y) { setSize(newWidth, newHeight); } } /** * Sets the receiver's minimum size to the size specified by the argument. * If the new minimum size is larger than the current size of the receiver, * the receiver is resized to the new minimum size. * * @param size the new minimum size for the receiver * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the point is null</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 1.3 */ public void setMinimumSize(Point size) { checkWidget(); if (size == null) { error(SWT.ERROR_NULL_ARGUMENT); } setMinimumSize(size.x, size.y); } /** * Returns a point describing the minimum receiver's size. The * x coordinate of the result is the minimum width of the receiver. * The y coordinate of the result is the minimum height of the * receiver. * * @return the receiver's size * * @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 1.3 */ public Point getMinimumSize() { checkWidget(); return new Point(minWidth, minHeight); } @Override public void setBounds(Rectangle bounds) { int newWidth = Math.max(bounds.width, minWidth); int newHeight = Math.max(bounds.height, minHeight); super.setBounds(new Rectangle(bounds.x, bounds.y, newWidth, newHeight)); } /** * Returns the instance of the ToolBar object representing the tool bar that can appear on the * trim of the shell. This will return <code>null</code> if the platform does not support tool * bars that not part of the content area of the shell, or if the style of the shell does not * support a tool bar. * <p> * * @return a ToolBar object representing the window's tool bar 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> * * @since 1.4 */ public ToolBar getToolBar() { checkWidget(); return null; } // /////////////////////////////////////////////// // Event listener registration and deregistration /** * Adds the listener to the collection of listeners who will * be notified when operations are performed on the receiver, * by sending the listener one of the messages defined in the * <code>ShellListener</code> interface. * * @param listener the listener which should be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</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> * * @see ShellListener * @see #removeShellListener */ public void addShellListener(ShellListener listener) { checkWidget(); if (listener == null) { error(SWT.ERROR_NULL_ARGUMENT); } TypedListener typedListener = new TypedListener(listener); addListener(SWT.Close, typedListener); addListener(SWT.Activate, typedListener); addListener(SWT.Deactivate, typedListener); } /** * Removes the listener from the collection of listeners who will * be notified when operations are performed on the receiver. * * @param listener the listener which should no longer be notified * * @exception IllegalArgumentException <ul> * <li>ERROR_NULL_ARGUMENT - if the listener is null</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> * * @see ShellListener * @see #addShellListener */ public void removeShellListener(ShellListener listener) { checkWidget(); if (listener == null) { error(SWT.ERROR_NULL_ARGUMENT); } removeListener(SWT.Close, listener); removeListener(SWT.Activate, listener); removeListener(SWT.Deactivate, listener); } /////////// // Disposal @Override void releaseChildren() { super.releaseChildren(); Shell[] dialogShells = internalGetShells(); for (int i = 0; i < dialogShells.length; i++) { dialogShells[i].dispose(); } Menu[] menus = getAdapter(MenuHolder.class).getMenus(); for (Menu menu : menus) { menu.dispose(); } if (toolTips != null) { for (int i = 0; i < toolTips.length; i++) { if (toolTips[i] != null) { toolTips[i].dispose(); } } } } @Override void releaseParent() { // Do not call super.releaseParent() // This method would try to remove a child-shell from its ControlHolder // but shells are currently not added to the ControlHolder of its parent display.removeShell(this); } //////////////////////////////////////////////////////////// // Methods to maintain activeControl and send ActivateEvents void setActiveControl(Control activateControl) { Control control = activateControl; if (control != null && control.isDisposed()) { control = null; } if (lastActive != null && lastActive.isDisposed()) { lastActive = null; } if (lastActive != control) { // Compute the list of controls to be activated and deactivated by finding // the first common parent control. Control[] activate = (control == null) ? new Control[0] : control.getPath(); Control[] deactivate = lastActive == null ? new Control[0] : lastActive.getPath(); lastActive = control; int index = 0; int length = Math.min(activate.length, deactivate.length); while (index < length && activate[index] == deactivate[index]) { index++; } // It is possible (but unlikely), that application code could have // destroyed some of the widgets. If this happens, keep processing those // widgets that are not disposed. for (int i = deactivate.length - 1; i >= index; --i) { if (!deactivate[i].isDisposed()) { deactivate[i].notifyListeners(SWT.Deactivate, new Event()); } } for (int i = activate.length - 1; i >= index; --i) { if (!activate[i].isDisposed()) { activate[i].notifyListeners(SWT.Activate, new Event()); } } } } private void bringToTop() { Object adapter = display.getAdapter(IDisplayAdapter.class); IDisplayAdapter displayAdapter = (IDisplayAdapter) adapter; displayAdapter.setFocusControl(this, true); // When a Shell is opened client-side the widget that is currently focused // loses its focus. This is unwanted in the case that the request that // opened the Shell sets the focus to some widget after opening the Shell. // The fix is to force the DisplayLCA to issue JavaScript that sets the // focus on the server-side focused widget. displayAdapter.invalidateFocus(); } //////////////// // Tab traversal @SuppressWarnings("unused") private boolean traverseGroup(boolean next) { // TODO [rh] fake implementation boolean result = false; if (getChildren().length > 0) { result = getChildren()[0].forceFocus(); } return result; } ////////////////////// // minimize / maximize // TODO [rst] Move these methods to class Decorations when implemented /** * Sets the minimized stated of the receiver. * If the argument is <code>true</code> causes the receiver * to switch to the minimized state, and if the argument is * <code>false</code> and the receiver was previously minimized, * causes the receiver to switch back to either the maximized * or normal states. * <!-- * <p> * Note: The result of intermixing calls to <code>setMaximized(true)</code> * and <code>setMinimized(true)</code> will vary by platform. Typically, * the behavior will match the platform user's expectations, but not * always. This should be avoided if possible. * </p> * --> * @param minimized the new maximized 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 #setMaximized */ public void setMinimized(boolean minimized) { checkWidget(); if (minimized) { mode |= MODE_MINIMIZED; } else { if ((mode & MODE_MINIMIZED) != 0) { setActive(); } mode &= ~MODE_MINIMIZED; } } /** * Sets the maximized state of the receiver. * If the argument is <code>true</code> causes the receiver * to switch to the maximized state, and if the argument is * <code>false</code> and the receiver was previously maximized, * causes the receiver to switch back to either the minimized * or normal states. * <!--<p> * Note: The result of intermixing calls to <code>setMaximized(true)</code> * and <code>setMinimized(true)</code> will vary by platform. Typically, * the behavior will match the platform user's expectations, but not * always. This should be avoided if possible. * </p> * --> * @param maximized the new maximized 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 #setMinimized */ public void setMaximized(boolean maximized) { checkWidget(); if ((mode & MODE_FULLSCREEN) == 0) { if (maximized) { if ((mode & MODE_MAXIMIZED) == 0) { setActive(); savedBounds = getBounds(); setBounds(display.getBounds(), false); } mode |= MODE_MAXIMIZED; mode &= ~MODE_MINIMIZED; } else { if ((mode & MODE_MAXIMIZED) != 0) { setBounds(savedBounds, false); } mode &= ~MODE_MAXIMIZED; } } } /** * Returns <code>true</code> if the receiver is currently * minimized, and false otherwise. * <p> * * @return the minimized 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 #setMinimized */ public boolean getMinimized() { checkWidget(); return (mode & MODE_MINIMIZED) != 0; } /** * Returns <code>true</code> if the receiver is currently * maximized, and false otherwise. * <p> * * @return the maximized 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 #setMaximized */ public boolean getMaximized() { checkWidget(); return (mode & MODE_FULLSCREEN) == 0 && (mode & MODE_MINIMIZED) == 0 && (mode & MODE_MAXIMIZED) != 0; } /** * Sets the full screen state of the receiver. * If the argument is <code>true</code> causes the receiver * to switch to the full screen state, and if the argument is * <code>false</code> and the receiver was previously switched * into full screen state, causes the receiver to switch back * to either the maximized or normal states. * <p> * Note: The result of intermixing calls to <code>setFullScreen(true)</code>, * <code>setMaximized(true)</code> and <code>setMinimized(true)</code> will * vary by platform. Typically, the behavior will match the platform user's * expectations, but not always. This should be avoided if possible. * </p> * * @param fullScreen the new fullscreen 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> * * @since 1.3 */ public void setFullScreen(boolean fullScreen) { checkWidget(); if (((mode & MODE_FULLSCREEN) != 0) != fullScreen) { if (fullScreen) { setActive(); if ((mode & MODE_MAXIMIZED) == 0) { savedBounds = getBounds(); } setBounds(display.getBounds(), false); mode |= MODE_FULLSCREEN; mode &= ~MODE_MINIMIZED; } else { if ((mode & MODE_MAXIMIZED) == 0) { setBounds(savedBounds, false); } mode &= ~MODE_FULLSCREEN; } layout(); } } /** * Returns <code>true</code> if the receiver is currently * in fullscreen state, and false otherwise. * <p> * * @return the fullscreen 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> * * @since 1.3 */ public boolean getFullScreen() { checkWidget(); return (mode & MODE_FULLSCREEN) != 0; } void fixShell(Shell newShell, Control control) { if (newShell != this && control == lastActive) { setActiveControl(null); } } /////////////////// // ToolTips support void createToolTip(ToolTip toolTip) { int id = 0; if (toolTips == null) { toolTips = new ToolTip[4]; } while (id < toolTips.length && toolTips[id] != null) { id++; } if (id == toolTips.length) { ToolTip[] newToolTips = new ToolTip[toolTips.length + 4]; System.arraycopy(toolTips, 0, newToolTips, 0, toolTips.length); toolTips = newToolTips; } toolTips[id] = toolTip; } void destroyToolTip(ToolTip toolTip) { boolean found = false; for (int i = 0; !found && i < toolTips.length; i++) { if (toolTips[i] == toolTip) { toolTips[i] = null; found = true; } } } private ToolTip[] getToolTips() { ToolTip[] result; if (toolTips == null) { result = new ToolTip[0]; } else { int count = 0; for (int i = 0; i < toolTips.length; i++) { if (toolTips[i] != null) { count++; } } result = new ToolTip[count]; int index = 0; for (int i = 0; i < toolTips.length; i++) { if (toolTips[i] != null) { result[index] = toolTips[i]; index++; } } } return result; } private static Shell checkParent(Shell parent) { if (parent != null && parent.isDisposed()) { SWT.error(SWT.ERROR_INVALID_ARGUMENT); } return parent; } /////////////////// // Skinning support @Override void reskinChildren(int flags) { Shell[] shells = getShells(); for (int i = 0; i < shells.length; i++) { Shell shell = shells[i]; if (shell != null) { shell.reskin(flags); } } super.reskinChildren(flags); } }