view dwtx/jface/window/Window.d @ 104:04b47443bb01

Reworked the collection uses to make use of a wrapper collection that is compatible to the Java Collections. These new wrappers now use the tango.util.containers instead of the tango.util.collections.
author Frank Benoit <benoit@tionex.de>
date Thu, 07 Aug 2008 15:01:33 +0200
parents 46a6e0e6ccd4
children
line wrap: on
line source

/*******************************************************************************
 * 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 dwtx.jface.window.Window;

import dwtx.jface.window.IShellProvider;
import dwtx.jface.window.WindowManager;
import dwtx.jface.window.SameShellProvider;


import dwt.DWT;
import dwt.events.ShellAdapter;
import dwt.events.ShellEvent;
import dwt.events.ShellListener;
import dwt.graphics.Image;
import dwt.graphics.Point;
import dwt.graphics.Rectangle;
import dwt.layout.GridLayout;
import dwt.widgets.Composite;
import dwt.widgets.Control;
import dwt.widgets.Display;
import dwt.widgets.Event;
import dwt.widgets.Layout;
import dwt.widgets.Listener;
import dwt.widgets.Monitor;
import dwt.widgets.Shell;
import dwtx.core.runtime.Assert;
import dwtx.jface.resource.JFaceResources;
import dwtx.jface.util.Geometry;
import dwtx.jface.util.IPropertyChangeListener;
import dwtx.jface.util.PropertyChangeEvent;

import dwt.dwthelper.utils;
import dwtx.dwtxhelper.Collection;
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 DWT 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 dwtx.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 DWT#NONE but it can also be DWT#LEFT_TO_RIGHT
     * or DWT#RIGHT_TO_LEFT
     */
    private static int orientation = DWT.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 = DWT.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 DWT 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, DWT.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(DWT.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 dwt.widgets.Decorations#setImages(dwt.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();

        dwt.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(DWT.DEFAULT, DWT.DEFAULT, true)</code>.
     *
     * @return the initial size of the shell
     */
    protected Point getInitialSize() {
        return shell.computeSize(DWT.DEFAULT, DWT.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 = DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL | DWT.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 = DWT.APPLICATION_MODAL | DWT.SYSTEM_MODAL | DWT.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>DWT.CLOSE|DWT.MIN|DWT.MAX|DWT.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 DWT 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(DWT.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 dwt.widgets.Decorations#setImages(dwt.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 dwt.widgets.Monitor.Monitor getClosestMonitor(Display toSearch, Point toFind) {
        int closest = Integer.MAX_VALUE;

        dwt.widgets.Monitor.Monitor[] monitors = toSearch.getMonitors();
        dwt.widgets.Monitor.Monitor result = monitors[0];

        for (int idx = 0; idx < monitors.length; idx++) {
            dwt.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);

        dwt.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 (DWT#NONE).
     *
     *
     * @return DWT#NONE, DWT.RIGHT_TO_LEFT or DWT.LEFT_TO_RIGHT
     * @see DWT#RIGHT_TO_LEFT
     * @see DWT#LEFT_TO_RIGHT
     * @see DWT#NONE
     * @since 3.1
     */
    public static int getDefaultOrientation() {
        return orientation;

    }

    /**
     * Sets the default orientation of windows.
     * @param defaultOrientation one of
     *  DWT#RIGHT_TO_LEFT, DWT#LEFT_TO_RIGHT ,DWT#NONE
     * @see DWT#RIGHT_TO_LEFT
     * @see DWT#LEFT_TO_RIGHT
     * @see DWT#NONE
     * @since 3.1
     */
    public static void setDefaultOrientation(int defaultOrientation) {
        orientation = defaultOrientation;

    }

}