Mercurial > projects > dwt2
diff org.eclipse.jface/src/org/eclipse/jface/window/Window.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children | 735224fcc45f |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/org.eclipse.jface/src/org/eclipse/jface/window/Window.d Sat Mar 14 18:23:29 2009 +0100 @@ -0,0 +1,1106 @@ +/******************************************************************************* + * 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 + * Port to the D programming language: + * Frank Benoit <benoit@tionex.de> + *******************************************************************************/ +module org.eclipse.jface.window.Window; + +import org.eclipse.jface.window.IShellProvider; +import org.eclipse.jface.window.WindowManager; +import org.eclipse.jface.window.SameShellProvider; + + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ShellAdapter; +import org.eclipse.swt.events.ShellEvent; +import org.eclipse.swt.events.ShellListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Layout; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Monitor; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.Geometry; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; + +import java.lang.all; +import java.util.ArrayList; +import java.util.Set; +import tango.io.Stdout; + +/** + * A JFace window is an object that has no visual representation (no widgets) + * until it is told to open. + * <p> + * Creating a window involves the following steps: + * <ul> + * <li>creating an instance of a concrete subclass of <code>Window</code> + * </li> + * <li>creating the window's shell and widget tree by calling + * <code>create</code> (optional)</li> + * <li>assigning the window to a window manager using + * <code>WindowManager.add</code> (optional)</li> + * <li>opening the window by calling <code>open</code></li> + * </ul> + * Opening the window will create its shell and widget tree if they have not + * already been created. When the window is closed, the shell and widget tree + * are disposed of and are no longer referenced, and the window is automatically + * removed from its window manager. A window may be reopened. + * </p> + * <p> + * The JFace window framework (this package) consists of this class, + * <code>Window</code>, the abstract base of all windows, and one concrete + * window classes (<code>ApplicationWindow</code>) which may also be + * subclassed. Clients may define additional window subclasses as required. + * </p> + * <p> + * The <code>Window</code> class provides methods that subclasses may + * override to configure the window, including: + * <ul> + * <li><code>close</code>- extend to free other SWT resources</li> + * <li><code>configureShell</code>- extend or reimplement to set shell + * properties before window opens</li> + * <li><code>createContents</code>- extend or reimplement to create controls + * before window opens</li> + * <li><code>getInitialSize</code>- reimplement to give the initial size for + * the shell</li> + * <li><code>getInitialLocation</code>- reimplement to give the initial + * location for the shell</li> + * <li><code>getShellListener</code>- extend or reimplement to receive shell + * events</li> + * <li><code>handleFontChange</code>- reimplement to respond to font changes + * </li> + * <li><code>handleShellCloseEvent</code>- extend or reimplement to handle + * shell closings</li> + * </ul> + * </p> + */ +public abstract class Window : IShellProvider { + + /** + * Standard return code constant (value 0) indicating that the window was + * opened. + * + * @see #open + */ + public static const int OK = 0; + + /** + * Standard return code constant (value 1) indicating that the window was + * canceled. + * + * @see #open + */ + public static const int CANCEL = 1; + + /** + * An array of images to be used for the window. It is expected that the + * array will contain the same icon rendered at different resolutions. + */ + private static Image[] defaultImages; + + /** + * This interface defines a Exception Handler which can be set as a global + * handler and will be called if an exception happens in the event loop. + */ + public interface IExceptionHandler { + /** + * Handle the exception. + * + * @param t + * The exception that occured. + */ + public void handleException(Exception t); + } + + /** + * Defines a default exception handler. + */ + private static class DefaultExceptionHandler : IExceptionHandler { + /* + * (non-Javadoc) + * + * @see org.eclipse.jface.window.Window.IExceptionHandler#handleException(java.lang.Throwable) + */ + public void handleException(Exception t) { + /+ + if (t instanceof ThreadDeath) { + // Don't catch ThreadDeath as this is a normal occurrence when + // the thread dies + throw (ThreadDeath) t; + } + +/ + // Try to keep running. + ExceptionPrintStackTrace(t); + } + } + + /** + * The exception handler for this application. + */ + private static IExceptionHandler exceptionHandler_; + private static IExceptionHandler exceptionHandler(){ + if( exceptionHandler_ is null ){ + synchronized if( exceptionHandler_ is null ){ + exceptionHandler_ = new DefaultExceptionHandler(); + } + } + return exceptionHandler_; + } + /** + * The default orientation of the window. By default + * it is SWT#NONE but it can also be SWT#LEFT_TO_RIGHT + * or SWT#RIGHT_TO_LEFT + */ + private static int orientation = SWT.NONE; + + /** + * Object used to locate the default parent for modal shells + */ + private static IShellProvider defaultModalParent_; + private static IShellProvider defaultModalParent(){ + if( defaultModalParent_ is null ){ + synchronized if( defaultModalParent_ is null ){ + defaultModalParent_ = new class IShellProvider { + public Shell getShell() { + Display d = Display.getCurrent(); + + if (d is null) { + return null; + } + + Shell parent = d.getActiveShell(); + + // Make sure we don't pick a parent that has a modal child (this can lock the app) + if (parent is null) { + // If this is a top-level window, then there must not be any open modal windows. + parent = getModalChild(Display.getCurrent().getShells()); + } else { + // If we picked a parent with a modal child, use the modal child instead + Shell modalChild = getModalChild(parent.getShells()); + if (modalChild !is null) { + parent = modalChild; + } + } + + return parent; + } + }; + } + } + return defaultModalParent_; + } + + /** + * Object that returns the parent shell. + */ + private IShellProvider parentShell; + + /** + * Shell style bits. + * + * @see #setShellStyle + */ + private int shellStyle = SWT.SHELL_TRIM; + + /** + * Window manager, or <code>null</code> if none. + * + * @see #setWindowManager + */ + private WindowManager windowManager; + + /** + * Window shell, or <code>null</code> if none. + */ + private Shell shell; + + /** + * Top level SWT control, or <code>null</code> if none + */ + private Control contents; + + /** + * Window return code; initially <code>OK</code>. + * + * @see #setReturnCode + */ + private int returnCode = OK; + + /** + * <code>true</code> if the <code>open</code> method should not return + * until the window closes, and <code>false</code> if the + * <code>open</code> method should return immediately; initially + * <code>false</code> (non-blocking). + * + * @see #setBlockOnOpen + */ + private bool block = false; + + /** + * Internal class for informing this window when fonts change. + */ + private class FontChangeListener : IPropertyChangeListener { + public void propertyChange(PropertyChangeEvent event) { + handleFontChange(event); + } + } + + /** + * Internal font change listener. + */ + private FontChangeListener fontChangeListener; + + /** + * Internal fields to detect if shell size has been set + */ + private bool resizeHasOccurred = false; + + private Listener resizeListener; + + /** + * Creates a window instance, whose shell will be created under the given + * parent shell. Note that the window will have no visual representation + * until it is told to open. By default, <code>open</code> does not block. + * + * @param parentShell + * the parent shell, or <code>null</code> to create a top-level + * shell. Try passing "(Shell)null" to this method instead of "null" + * if your compiler complains about an ambiguity error. + * @see #setBlockOnOpen + * @see #getDefaultOrientation() + */ + protected this(Shell parentShell) { + this(new SameShellProvider(parentShell)); + + if(parentShell is null) { + setShellStyle(getShellStyle() | getDefaultOrientation()); + } + } + + /** + * Creates a new window which will create its shell as a child of whatever + * the given shellProvider returns. + * + * @param shellProvider object that will return the current parent shell. Not null. + * + * @since 3.1 + */ + protected this(IShellProvider shellProvider) { + Assert.isNotNull(cast(Object)shellProvider); + this.parentShell = shellProvider; + } + + /** + * Determines if the window should handle the close event or do nothing. + * <p> + * The default implementation of this framework method returns + * <code>true</code>, which will allow the + * <code>handleShellCloseEvent</code> method to be called. Subclasses may + * extend or reimplement. + * </p> + * + * @return whether the window should handle the close event. + */ + protected bool canHandleShellCloseEvent() { + return true; + } + + /** + * Closes this window, disposes its shell, and removes this window from its + * window manager (if it has one). + * <p> + * This framework method may be extended (<code>super.close</code> must + * be called). + * </p> + * <p> + * Note that in order to prevent recursive calls to this method + * it does not call <code>Shell#close()</code>. As a result <code>ShellListener</code>s + * will not receive a <code>shellClosed</code> event. + * </p> + * + * @return <code>true</code> if the window is (or was already) closed, and + * <code>false</code> if it is still open + */ + public bool close() { + + // stop listening for font changes + if (fontChangeListener !is null) { + JFaceResources.getFontRegistry().removeListener(fontChangeListener); + fontChangeListener = null; + } + + // remove this window from a window manager if it has one + if (windowManager !is null) { + windowManager.remove(this); + windowManager = null; + } + + if (shell is null || shell.isDisposed()) { + return true; + } + + // If we "close" the shell recursion will occur. + // Instead, we need to "dispose" the shell to remove it from the + // display. + shell.dispose(); + shell = null; + contents = null; + + return true; + } + + /** + * Configures the given shell in preparation for opening this window in it. + * <p> + * The default implementation of this framework method sets the shell's + * image and gives it a grid layout. Subclasses may extend or reimplement. + * </p> + * + * @param newShell + * the shell + */ + protected void configureShell(Shell newShell) { + + // The single image version of this code had a comment related to bug + // 46624, + // and some code that did nothing if the stored image was already + // disposed. + // The equivalent in the multi-image version seems to be to remove the + // disposed images from the array passed to the shell. + if (defaultImages !is null && defaultImages.length > 0) { + ArrayList nonDisposedImages = new ArrayList(defaultImages.length); + for (int i = 0; i < defaultImages.length; ++i) { + if (defaultImages[i] !is null && !defaultImages[i].isDisposed()) { + nonDisposedImages.add(defaultImages[i]); + } + } + + if (nonDisposedImages.size() <= 0) { + Stderr.formatln("Window.configureShell: images disposed"); //$NON-NLS-1$ + } else { + newShell.setImages(arraycast!(Image)(nonDisposedImages.toArray())); + } + } + + Layout layout = getLayout(); + if (layout !is null) { + newShell.setLayout(layout); + } + } + + /** + * Creates the layout for the shell. The layout created here will be + * attached to the composite passed into createContents. The default + * implementation returns a GridLayout with no margins. Subclasses that + * change the layout type by overriding this method should also override + * createContents. + * + * <p> + * A return value of null indicates that no layout should be attached to the + * composite. In this case, the layout may be attached within + * createContents. + * </p> + * + * @return a newly created Layout or null if no layout should be attached. + * @since 3.0 + */ + protected Layout getLayout() { + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; + layout.marginWidth = 0; + return layout; + } + + /** + * Constrain the shell size to be no larger than the display bounds. + * + * @since 2.0 + */ + protected void constrainShellSize() { + // limit the shell size to the display size + Rectangle bounds = shell.getBounds(); + Rectangle constrained = getConstrainedShellBounds(bounds); + if (!bounds.opEquals(constrained)) { + shell.setBounds(constrained); + } + } + + /** + * Creates this window's widgetry in a new top-level shell. + * <p> + * The default implementation of this framework method creates this window's + * shell (by calling <code>createShell</code>), and its controls (by + * calling <code>createContents</code>), then initializes this window's + * shell bounds (by calling <code>initializeBounds</code>). + * </p> + */ + public void create() { + shell = createShell(); + contents = createContents(shell); + + //initialize the bounds of the shell to that appropriate for the + // contents + initializeBounds(); + } + + /** + * Creates and returns this window's contents. Subclasses may attach any + * number of children to the parent. As a convenience, the return value of + * this method will be remembered and returned by subsequent calls to + * getContents(). Subclasses may modify the parent's layout if they overload + * getLayout() to return null. + * + * <p> + * It is common practise to create and return a single composite that + * contains the entire window contents. + * </p> + * + * <p> + * The default implementation of this framework method creates an instance + * of <code>Composite</code>. Subclasses may override. + * </p> + * + * @param parent + * the parent composite for the controls in this window. The type + * of layout used is determined by getLayout() + * + * @return the control that will be returned by subsequent calls to + * getContents() + */ + protected Control createContents(Composite parent) { + // by default, just create a composite + return new Composite(parent, SWT.NONE); + } + + /** + * Creates and returns this window's shell. + * <p> + * The default implementation of this framework method creates a new shell + * and configures it using <code/>configureShell</code>. Rather than + * override this method, subclasses should instead override + * <code/>configureShell</code>. + * </p> + * + * @return the shell + */ + protected final Shell createShell() { + + Shell newParent = getParentShell(); + if(newParent !is null && newParent.isDisposed()){ + parentShell = new SameShellProvider(null); + newParent = getParentShell();//Find a better parent + } + + //Create the shell + Shell newShell = new Shell(newParent, getShellStyle()); + + resizeListener = new class Listener { + public void handleEvent(Event e) { + resizeHasOccurred = true; + } + }; + + newShell.addListener(SWT.Resize, resizeListener); + newShell.setData(this); + + //Add a listener + newShell.addShellListener(getShellListener()); + + //Set the layout + configureShell(newShell); + + //Register for font changes + if (fontChangeListener is null) { + fontChangeListener = new FontChangeListener(); + } + JFaceResources.getFontRegistry().addListener(fontChangeListener); + + return newShell; + } + + /** + * Returns the top level control for this window. The parent of this control + * is the shell. + * + * @return the top level control, or <code>null</code> if this window's + * control has not been created yet + */ + protected Control getContents() { + return contents; + } + + /** + * Returns the default image. This is the image that will be used for + * windows that have no shell image at the time they are opened. There is no + * default image unless one is installed via <code>setDefaultImage</code>. + * + * @return the default image, or <code>null</code> if none + * @see #setDefaultImage + */ + public static Image getDefaultImage() { + return (defaultImages is null || defaultImages.length < 1) ? null + : defaultImages[0]; + } + + /** + * Returns the array of default images to use for newly opened windows. It + * is expected that the array will contain the same icon rendered at + * different resolutions. + * + * @see org.eclipse.swt.widgets.Decorations#setImages(org.eclipse.swt.graphics.Image[]) + * + * @return the array of images to be used when a new window is opened + * @see #setDefaultImages + * @since 3.0 + */ + public static Image[] getDefaultImages() { + return (defaultImages is null ? new Image[0] : defaultImages); + } + + /** + * Returns the initial location to use for the shell. The default + * implementation centers the shell horizontally (1/2 of the difference to + * the left and 1/2 to the right) and vertically (1/3 above and 2/3 below) + * relative to the parent shell, or display bounds if there is no parent + * shell. + * + * @param initialSize + * the initial size of the shell, as returned by + * <code>getInitialSize</code>. + * @return the initial location of the shell + */ + protected Point getInitialLocation(Point initialSize) { + Composite parent = shell.getParent(); + + org.eclipse.swt.widgets.Monitor.Monitor monitor = shell.getDisplay().getPrimaryMonitor(); + if (parent !is null) { + monitor = parent.getMonitor(); + } + + Rectangle monitorBounds = monitor.getClientArea(); + Point centerPoint; + if (parent !is null) { + centerPoint = Geometry.centerPoint(parent.getBounds()); + } else { + centerPoint = Geometry.centerPoint(monitorBounds); + } + + return new Point(centerPoint.x - (initialSize.x / 2), Math.max( + monitorBounds.y, Math.min(centerPoint.y + - (initialSize.y * 2 / 3), monitorBounds.y + + monitorBounds.height - initialSize.y))); + } + + /** + * Returns the initial size to use for the shell. The default implementation + * returns the preferred size of the shell, using + * <code>Shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true)</code>. + * + * @return the initial size of the shell + */ + protected Point getInitialSize() { + return shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true); + } + + /** + * Returns the most specific modal child from the given list of Shells. + * + * @param toSearch shells to search for modal children + * @return the most specific modal child, or null if none + * + * @since 3.1 + */ + private static Shell getModalChild(Shell[] toSearch) { + int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL | SWT.PRIMARY_MODAL; + + for (int i = toSearch.length - 1; i >= 0; i--) { + Shell shell = toSearch[i]; + + // Check if this shell has a modal child + Shell[] children = shell.getShells(); + Shell modalChild = getModalChild(children); + if (modalChild !is null) { + return modalChild; + } + + // If not, check if this shell is modal itself + if (shell.isVisible() && (shell.getStyle() & modal) !is 0) { + return shell; + } + } + + return null; + } + + /** + * Returns parent shell, under which this window's shell is created. + * + * @return the parent shell, or <code>null</code> if there is no parent + * shell + */ + protected Shell getParentShell() { + Shell parent = parentShell.getShell(); + + int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL | SWT.PRIMARY_MODAL; + + if ((getShellStyle() & modal) !is 0) { + // If this is a modal shell with no parent, pick a shell using defaultModalParent. + if (parent is null) { + parent = defaultModalParent.getShell(); + } + } + + return parent; + } + + /** + * Returns this window's return code. A window's return codes are + * window-specific, although two standard return codes are predefined: + * <code>OK</code> and <code>CANCEL</code>. + * + * @return the return code + */ + public int getReturnCode() { + return returnCode; + } + + /** + * Returns this window's shell. + * + * @return this window's shell, or <code>null</code> if this window's + * shell has not been created yet + */ + public Shell getShell() { + return shell; + } + + /** + * Returns a shell listener. This shell listener gets registered with this + * window's shell. + * <p> + * The default implementation of this framework method returns a new + * listener that makes this window the active window for its window manager + * (if it has one) when the shell is activated, and calls the framework + * method <code>handleShellCloseEvent</code> when the shell is closed. + * Subclasses may extend or reimplement. + * </p> + * + * @return a shell listener + */ + protected ShellListener getShellListener() { + return new class ShellAdapter { + public void shellClosed(ShellEvent event) { + event.doit = false; // don't close now + if (canHandleShellCloseEvent()) { + handleShellCloseEvent(); + } + } + }; + } + + /** + * Returns the shell style bits. + * <p> + * The default value is <code>SWT.CLOSE|SWT.MIN|SWT.MAX|SWT.RESIZE</code>. + * Subclassers should call <code>setShellStyle</code> to change this + * value, rather than overriding this method. + * </p> + * + * @return the shell style bits + */ + protected int getShellStyle() { + return shellStyle; + } + + /** + * Returns the window manager of this window. + * + * @return the WindowManager, or <code>null</code> if none + */ + public WindowManager getWindowManager() { + return windowManager; + } + + /** + * Notifies of a font property change. + * <p> + * The default implementation of this framework method does nothing. + * Subclasses may reimplement. + * </p> + * + * @param event + * the property change event detailing what changed + */ + protected void handleFontChange(PropertyChangeEvent event) { + // do nothing + } + + /** + * Notifies that the window's close button was pressed, the close menu was + * selected, or the ESCAPE key pressed. + * <p> + * The default implementation of this framework method sets the window's + * return code to <code>CANCEL</code> and closes the window using + * <code>close</code>. Subclasses may extend or reimplement. + * </p> + */ + protected void handleShellCloseEvent() { + setReturnCode(CANCEL); + close(); + } + + /** + * Initializes the location and size of this window's SWT shell after it has + * been created. + * <p> + * This framework method is called by the <code>create</code> framework + * method. The default implementation calls <code>getInitialSize</code> + * and <code>getInitialLocation</code> and passes the results to + * <code>Shell.setBounds</code>. This is only done if the bounds of the + * shell have not already been modified. Subclasses may extend or + * reimplement. + * </p> + */ + protected void initializeBounds() { + if (resizeListener !is null) { + shell.removeListener(SWT.Resize, resizeListener); + } + if (resizeHasOccurred) { // Check if shell size has been set already. + return; + } + + Point size = getInitialSize(); + Point location = getInitialLocation(size); + shell.setBounds(getConstrainedShellBounds(new Rectangle(location.x, + location.y, size.x, size.y))); + } + + /** + * Opens this window, creating it first if it has not yet been created. + * <p> + * If this window has been configured to block on open ( + * <code>setBlockOnOpen</code>), this method waits until the window is + * closed by the end user, and then it returns the window's return code; + * otherwise, this method returns immediately. A window's return codes are + * window-specific, although two standard return codes are predefined: + * <code>OK</code> and <code>CANCEL</code>. + * </p> + * + * @return the return code + * + * @see #create() + */ + public int open() { + + if (shell is null || shell.isDisposed()) { + shell = null; + // create the window + create(); + } + + // limit the shell size to the display size + constrainShellSize(); + + // open the window + shell.open(); + + // run the event loop if specified + if (block) { + runEventLoop(shell); + } + + return returnCode; + } + + /** + * Runs the event loop for the given shell. + * + * @param loopShell + * the shell + */ + private void runEventLoop(Shell loopShell) { + + //Use the display provided by the shell if possible + Display display; + if (shell is null) { + display = Display.getCurrent(); + } else { + display = loopShell.getDisplay(); + } + + while (loopShell !is null && !loopShell.isDisposed()) { + try { + if (!display.readAndDispatch()) { + display.sleep(); + } + } catch (Exception e) { + exceptionHandler.handleException(e); + } + } + display.update(); + } + + /** + * Sets whether the <code>open</code> method should block until the window + * closes. + * + * @param shouldBlock + * <code>true</code> if the <code>open</code> method should + * not return until the window closes, and <code>false</code> + * if the <code>open</code> method should return immediately + */ + public void setBlockOnOpen(bool shouldBlock) { + block = shouldBlock; + } + + /** + * Sets the default image. This is the image that will be used for windows + * that have no shell image at the time they are opened. There is no default + * image unless one is installed via this method. + * + * @param image + * the default image, or <code>null</code> if none + */ + public static void setDefaultImage(Image image) { + defaultImages = image is null ? null : [ image ]; + } + + /** + * Sets the array of default images to use for newly opened windows. It is + * expected that the array will contain the same icon rendered at different + * resolutions. + * + * @see org.eclipse.swt.widgets.Decorations#setImages(org.eclipse.swt.graphics.Image[]) + * + * @param images + * the array of images to be used when this window is opened + * @since 3.0 + */ + public static void setDefaultImages(Image[] images) { + Image[] newArray = new Image[images.length]; + System.arraycopy(images, 0, newArray, 0, newArray.length); + defaultImages = newArray; + } + + /** + * Changes the parent shell. This is only safe to use when the shell is not + * yet realized (i.e., created). Once the shell is created, it must be + * disposed (i.e., closed) before this method can be called. + * + * @param newParentShell + * The new parent shell; this value may be <code>null</code> if + * there is to be no parent. + * @since 3.1 + */ + protected void setParentShell(Shell newParentShell) { + Assert.isTrue((shell is null), "There must not be an existing shell."); //$NON-NLS-1$ + parentShell = new SameShellProvider(newParentShell); + } + + /** + * Sets this window's return code. The return code is automatically returned + * by <code>open</code> if block on open is enabled. For non-blocking + * opens, the return code needs to be retrieved manually using + * <code>getReturnCode</code>. + * + * @param code + * the return code + */ + protected void setReturnCode(int code) { + returnCode = code; + } + + /** + * Returns the monitor whose client area contains the given point. If no + * monitor contains the point, returns the monitor that is closest to the + * point. If this is ever made public, it should be moved into a separate + * utility class. + * + * @param toSearch + * point to find (display coordinates) + * @param toFind + * point to find (display coordinates) + * @return the montor closest to the given point + */ + private static org.eclipse.swt.widgets.Monitor.Monitor getClosestMonitor(Display toSearch, Point toFind) { + int closest = Integer.MAX_VALUE; + + org.eclipse.swt.widgets.Monitor.Monitor[] monitors = toSearch.getMonitors(); + org.eclipse.swt.widgets.Monitor.Monitor result = monitors[0]; + + for (int idx = 0; idx < monitors.length; idx++) { + org.eclipse.swt.widgets.Monitor.Monitor current = monitors[idx]; + + Rectangle clientArea = current.getClientArea(); + + if (clientArea.contains(toFind)) { + return current; + } + + int distance = Geometry.distanceSquared(Geometry + .centerPoint(clientArea), toFind); + if (distance < closest) { + closest = distance; + result = current; + } + } + + return result; + } + + /** + * Given the desired position of the window, this method returns an adjusted + * position such that the window is no larger than its monitor, and does not + * extend beyond the edge of the monitor. This is used for computing the + * initial window position, and subclasses can use this as a utility method + * if they want to limit the region in which the window may be moved. + * + * @param preferredSize + * the preferred position of the window + * @return a rectangle as close as possible to preferredSize that does not + * extend outside the monitor + * + * @since 3.0 + */ + protected Rectangle getConstrainedShellBounds(Rectangle preferredSize) { + Rectangle result = new Rectangle(preferredSize.x, preferredSize.y, + preferredSize.width, preferredSize.height); + + org.eclipse.swt.widgets.Monitor.Monitor mon = getClosestMonitor(getShell().getDisplay(), Geometry + .centerPoint(result)); + + Rectangle bounds = mon.getClientArea(); + + if (result.height > bounds.height) { + result.height = bounds.height; + } + + if (result.width > bounds.width) { + result.width = bounds.width; + } + + result.x = Math.max(bounds.x, Math.min(result.x, bounds.x + + bounds.width - result.width)); + result.y = Math.max(bounds.y, Math.min(result.y, bounds.y + + bounds.height - result.height)); + + return result; + } + + /** + * Sets the shell style bits. This method has no effect after the shell is + * created. + * <p> + * The shell style bits are used by the framework method + * <code>createShell</code> when creating this window's shell. + * </p> + * + * @param newShellStyle + * the new shell style bits + */ + protected void setShellStyle(int newShellStyle) { + shellStyle = newShellStyle; + } + + /** + * Sets the window manager of this window. + * <p> + * Note that this method is used by <code>WindowManager</code> to maintain + * a backpointer. Clients must not call the method directly. + * </p> + * + * @param manager + * the window manager, or <code>null</code> if none + */ + public void setWindowManager(WindowManager manager) { + windowManager = manager; + + // Code to detect invalid usage + + if (manager !is null) { + Window[] windows = manager.getWindows(); + for (int i = 0; i < windows.length; i++) { + if (windows[i] is this) { + return; + } + } + manager.add(this); + } + } + + /** + * Sets the exception handler for this application. + * <p> + * Note that the handler may only be set once. Subsequent calls to this method will be + * ignored. + * <p> + * + * @param handler + * the exception handler for the application. + */ + public static void setExceptionHandler(IExceptionHandler handler) { + if ( cast(DefaultExceptionHandler)exceptionHandler ) { + exceptionHandler_ = handler; + } + } + + /** + * Sets the default parent for modal Windows. This will be used to locate + * the parent for any modal Window constructed with a null parent. + * + * @param provider shell provider that will be used to locate the parent shell + * whenever a Window is created with a null parent + * @since 3.1 + */ + public static void setDefaultModalParent(IShellProvider provider) { + defaultModalParent_ = provider; + } + + /** + * Gets the default orientation for windows. If it is not + * set the default value will be unspecified (SWT#NONE). + * + * + * @return SWT#NONE, SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT + * @see SWT#RIGHT_TO_LEFT + * @see SWT#LEFT_TO_RIGHT + * @see SWT#NONE + * @since 3.1 + */ + public static int getDefaultOrientation() { + return orientation; + + } + + /** + * Sets the default orientation of windows. + * @param defaultOrientation one of + * SWT#RIGHT_TO_LEFT, SWT#LEFT_TO_RIGHT ,SWT#NONE + * @see SWT#RIGHT_TO_LEFT + * @see SWT#LEFT_TO_RIGHT + * @see SWT#NONE + * @since 3.1 + */ + public static void setDefaultOrientation(int defaultOrientation) { + orientation = defaultOrientation; + + } + +}