comparison 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
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
12 *******************************************************************************/
13 module org.eclipse.jface.window.Window;
14
15 import org.eclipse.jface.window.IShellProvider;
16 import org.eclipse.jface.window.WindowManager;
17 import org.eclipse.jface.window.SameShellProvider;
18
19
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.ShellAdapter;
22 import org.eclipse.swt.events.ShellEvent;
23 import org.eclipse.swt.events.ShellListener;
24 import org.eclipse.swt.graphics.Image;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.graphics.Rectangle;
27 import org.eclipse.swt.layout.GridLayout;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Display;
31 import org.eclipse.swt.widgets.Event;
32 import org.eclipse.swt.widgets.Layout;
33 import org.eclipse.swt.widgets.Listener;
34 import org.eclipse.swt.widgets.Monitor;
35 import org.eclipse.swt.widgets.Shell;
36 import org.eclipse.core.runtime.Assert;
37 import org.eclipse.jface.resource.JFaceResources;
38 import org.eclipse.jface.util.Geometry;
39 import org.eclipse.jface.util.IPropertyChangeListener;
40 import org.eclipse.jface.util.PropertyChangeEvent;
41
42 import java.lang.all;
43 import java.util.ArrayList;
44 import java.util.Set;
45 import tango.io.Stdout;
46
47 /**
48 * A JFace window is an object that has no visual representation (no widgets)
49 * until it is told to open.
50 * <p>
51 * Creating a window involves the following steps:
52 * <ul>
53 * <li>creating an instance of a concrete subclass of <code>Window</code>
54 * </li>
55 * <li>creating the window's shell and widget tree by calling
56 * <code>create</code> (optional)</li>
57 * <li>assigning the window to a window manager using
58 * <code>WindowManager.add</code> (optional)</li>
59 * <li>opening the window by calling <code>open</code></li>
60 * </ul>
61 * Opening the window will create its shell and widget tree if they have not
62 * already been created. When the window is closed, the shell and widget tree
63 * are disposed of and are no longer referenced, and the window is automatically
64 * removed from its window manager. A window may be reopened.
65 * </p>
66 * <p>
67 * The JFace window framework (this package) consists of this class,
68 * <code>Window</code>, the abstract base of all windows, and one concrete
69 * window classes (<code>ApplicationWindow</code>) which may also be
70 * subclassed. Clients may define additional window subclasses as required.
71 * </p>
72 * <p>
73 * The <code>Window</code> class provides methods that subclasses may
74 * override to configure the window, including:
75 * <ul>
76 * <li><code>close</code>- extend to free other SWT resources</li>
77 * <li><code>configureShell</code>- extend or reimplement to set shell
78 * properties before window opens</li>
79 * <li><code>createContents</code>- extend or reimplement to create controls
80 * before window opens</li>
81 * <li><code>getInitialSize</code>- reimplement to give the initial size for
82 * the shell</li>
83 * <li><code>getInitialLocation</code>- reimplement to give the initial
84 * location for the shell</li>
85 * <li><code>getShellListener</code>- extend or reimplement to receive shell
86 * events</li>
87 * <li><code>handleFontChange</code>- reimplement to respond to font changes
88 * </li>
89 * <li><code>handleShellCloseEvent</code>- extend or reimplement to handle
90 * shell closings</li>
91 * </ul>
92 * </p>
93 */
94 public abstract class Window : IShellProvider {
95
96 /**
97 * Standard return code constant (value 0) indicating that the window was
98 * opened.
99 *
100 * @see #open
101 */
102 public static const int OK = 0;
103
104 /**
105 * Standard return code constant (value 1) indicating that the window was
106 * canceled.
107 *
108 * @see #open
109 */
110 public static const int CANCEL = 1;
111
112 /**
113 * An array of images to be used for the window. It is expected that the
114 * array will contain the same icon rendered at different resolutions.
115 */
116 private static Image[] defaultImages;
117
118 /**
119 * This interface defines a Exception Handler which can be set as a global
120 * handler and will be called if an exception happens in the event loop.
121 */
122 public interface IExceptionHandler {
123 /**
124 * Handle the exception.
125 *
126 * @param t
127 * The exception that occured.
128 */
129 public void handleException(Exception t);
130 }
131
132 /**
133 * Defines a default exception handler.
134 */
135 private static class DefaultExceptionHandler : IExceptionHandler {
136 /*
137 * (non-Javadoc)
138 *
139 * @see org.eclipse.jface.window.Window.IExceptionHandler#handleException(java.lang.Throwable)
140 */
141 public void handleException(Exception t) {
142 /+
143 if (t instanceof ThreadDeath) {
144 // Don't catch ThreadDeath as this is a normal occurrence when
145 // the thread dies
146 throw (ThreadDeath) t;
147 }
148 +/
149 // Try to keep running.
150 ExceptionPrintStackTrace(t);
151 }
152 }
153
154 /**
155 * The exception handler for this application.
156 */
157 private static IExceptionHandler exceptionHandler_;
158 private static IExceptionHandler exceptionHandler(){
159 if( exceptionHandler_ is null ){
160 synchronized if( exceptionHandler_ is null ){
161 exceptionHandler_ = new DefaultExceptionHandler();
162 }
163 }
164 return exceptionHandler_;
165 }
166 /**
167 * The default orientation of the window. By default
168 * it is SWT#NONE but it can also be SWT#LEFT_TO_RIGHT
169 * or SWT#RIGHT_TO_LEFT
170 */
171 private static int orientation = SWT.NONE;
172
173 /**
174 * Object used to locate the default parent for modal shells
175 */
176 private static IShellProvider defaultModalParent_;
177 private static IShellProvider defaultModalParent(){
178 if( defaultModalParent_ is null ){
179 synchronized if( defaultModalParent_ is null ){
180 defaultModalParent_ = new class IShellProvider {
181 public Shell getShell() {
182 Display d = Display.getCurrent();
183
184 if (d is null) {
185 return null;
186 }
187
188 Shell parent = d.getActiveShell();
189
190 // Make sure we don't pick a parent that has a modal child (this can lock the app)
191 if (parent is null) {
192 // If this is a top-level window, then there must not be any open modal windows.
193 parent = getModalChild(Display.getCurrent().getShells());
194 } else {
195 // If we picked a parent with a modal child, use the modal child instead
196 Shell modalChild = getModalChild(parent.getShells());
197 if (modalChild !is null) {
198 parent = modalChild;
199 }
200 }
201
202 return parent;
203 }
204 };
205 }
206 }
207 return defaultModalParent_;
208 }
209
210 /**
211 * Object that returns the parent shell.
212 */
213 private IShellProvider parentShell;
214
215 /**
216 * Shell style bits.
217 *
218 * @see #setShellStyle
219 */
220 private int shellStyle = SWT.SHELL_TRIM;
221
222 /**
223 * Window manager, or <code>null</code> if none.
224 *
225 * @see #setWindowManager
226 */
227 private WindowManager windowManager;
228
229 /**
230 * Window shell, or <code>null</code> if none.
231 */
232 private Shell shell;
233
234 /**
235 * Top level SWT control, or <code>null</code> if none
236 */
237 private Control contents;
238
239 /**
240 * Window return code; initially <code>OK</code>.
241 *
242 * @see #setReturnCode
243 */
244 private int returnCode = OK;
245
246 /**
247 * <code>true</code> if the <code>open</code> method should not return
248 * until the window closes, and <code>false</code> if the
249 * <code>open</code> method should return immediately; initially
250 * <code>false</code> (non-blocking).
251 *
252 * @see #setBlockOnOpen
253 */
254 private bool block = false;
255
256 /**
257 * Internal class for informing this window when fonts change.
258 */
259 private class FontChangeListener : IPropertyChangeListener {
260 public void propertyChange(PropertyChangeEvent event) {
261 handleFontChange(event);
262 }
263 }
264
265 /**
266 * Internal font change listener.
267 */
268 private FontChangeListener fontChangeListener;
269
270 /**
271 * Internal fields to detect if shell size has been set
272 */
273 private bool resizeHasOccurred = false;
274
275 private Listener resizeListener;
276
277 /**
278 * Creates a window instance, whose shell will be created under the given
279 * parent shell. Note that the window will have no visual representation
280 * until it is told to open. By default, <code>open</code> does not block.
281 *
282 * @param parentShell
283 * the parent shell, or <code>null</code> to create a top-level
284 * shell. Try passing "(Shell)null" to this method instead of "null"
285 * if your compiler complains about an ambiguity error.
286 * @see #setBlockOnOpen
287 * @see #getDefaultOrientation()
288 */
289 protected this(Shell parentShell) {
290 this(new SameShellProvider(parentShell));
291
292 if(parentShell is null) {
293 setShellStyle(getShellStyle() | getDefaultOrientation());
294 }
295 }
296
297 /**
298 * Creates a new window which will create its shell as a child of whatever
299 * the given shellProvider returns.
300 *
301 * @param shellProvider object that will return the current parent shell. Not null.
302 *
303 * @since 3.1
304 */
305 protected this(IShellProvider shellProvider) {
306 Assert.isNotNull(cast(Object)shellProvider);
307 this.parentShell = shellProvider;
308 }
309
310 /**
311 * Determines if the window should handle the close event or do nothing.
312 * <p>
313 * The default implementation of this framework method returns
314 * <code>true</code>, which will allow the
315 * <code>handleShellCloseEvent</code> method to be called. Subclasses may
316 * extend or reimplement.
317 * </p>
318 *
319 * @return whether the window should handle the close event.
320 */
321 protected bool canHandleShellCloseEvent() {
322 return true;
323 }
324
325 /**
326 * Closes this window, disposes its shell, and removes this window from its
327 * window manager (if it has one).
328 * <p>
329 * This framework method may be extended (<code>super.close</code> must
330 * be called).
331 * </p>
332 * <p>
333 * Note that in order to prevent recursive calls to this method
334 * it does not call <code>Shell#close()</code>. As a result <code>ShellListener</code>s
335 * will not receive a <code>shellClosed</code> event.
336 * </p>
337 *
338 * @return <code>true</code> if the window is (or was already) closed, and
339 * <code>false</code> if it is still open
340 */
341 public bool close() {
342
343 // stop listening for font changes
344 if (fontChangeListener !is null) {
345 JFaceResources.getFontRegistry().removeListener(fontChangeListener);
346 fontChangeListener = null;
347 }
348
349 // remove this window from a window manager if it has one
350 if (windowManager !is null) {
351 windowManager.remove(this);
352 windowManager = null;
353 }
354
355 if (shell is null || shell.isDisposed()) {
356 return true;
357 }
358
359 // If we "close" the shell recursion will occur.
360 // Instead, we need to "dispose" the shell to remove it from the
361 // display.
362 shell.dispose();
363 shell = null;
364 contents = null;
365
366 return true;
367 }
368
369 /**
370 * Configures the given shell in preparation for opening this window in it.
371 * <p>
372 * The default implementation of this framework method sets the shell's
373 * image and gives it a grid layout. Subclasses may extend or reimplement.
374 * </p>
375 *
376 * @param newShell
377 * the shell
378 */
379 protected void configureShell(Shell newShell) {
380
381 // The single image version of this code had a comment related to bug
382 // 46624,
383 // and some code that did nothing if the stored image was already
384 // disposed.
385 // The equivalent in the multi-image version seems to be to remove the
386 // disposed images from the array passed to the shell.
387 if (defaultImages !is null && defaultImages.length > 0) {
388 ArrayList nonDisposedImages = new ArrayList(defaultImages.length);
389 for (int i = 0; i < defaultImages.length; ++i) {
390 if (defaultImages[i] !is null && !defaultImages[i].isDisposed()) {
391 nonDisposedImages.add(defaultImages[i]);
392 }
393 }
394
395 if (nonDisposedImages.size() <= 0) {
396 Stderr.formatln("Window.configureShell: images disposed"); //$NON-NLS-1$
397 } else {
398 newShell.setImages(arraycast!(Image)(nonDisposedImages.toArray()));
399 }
400 }
401
402 Layout layout = getLayout();
403 if (layout !is null) {
404 newShell.setLayout(layout);
405 }
406 }
407
408 /**
409 * Creates the layout for the shell. The layout created here will be
410 * attached to the composite passed into createContents. The default
411 * implementation returns a GridLayout with no margins. Subclasses that
412 * change the layout type by overriding this method should also override
413 * createContents.
414 *
415 * <p>
416 * A return value of null indicates that no layout should be attached to the
417 * composite. In this case, the layout may be attached within
418 * createContents.
419 * </p>
420 *
421 * @return a newly created Layout or null if no layout should be attached.
422 * @since 3.0
423 */
424 protected Layout getLayout() {
425 GridLayout layout = new GridLayout();
426 layout.marginHeight = 0;
427 layout.marginWidth = 0;
428 return layout;
429 }
430
431 /**
432 * Constrain the shell size to be no larger than the display bounds.
433 *
434 * @since 2.0
435 */
436 protected void constrainShellSize() {
437 // limit the shell size to the display size
438 Rectangle bounds = shell.getBounds();
439 Rectangle constrained = getConstrainedShellBounds(bounds);
440 if (!bounds.opEquals(constrained)) {
441 shell.setBounds(constrained);
442 }
443 }
444
445 /**
446 * Creates this window's widgetry in a new top-level shell.
447 * <p>
448 * The default implementation of this framework method creates this window's
449 * shell (by calling <code>createShell</code>), and its controls (by
450 * calling <code>createContents</code>), then initializes this window's
451 * shell bounds (by calling <code>initializeBounds</code>).
452 * </p>
453 */
454 public void create() {
455 shell = createShell();
456 contents = createContents(shell);
457
458 //initialize the bounds of the shell to that appropriate for the
459 // contents
460 initializeBounds();
461 }
462
463 /**
464 * Creates and returns this window's contents. Subclasses may attach any
465 * number of children to the parent. As a convenience, the return value of
466 * this method will be remembered and returned by subsequent calls to
467 * getContents(). Subclasses may modify the parent's layout if they overload
468 * getLayout() to return null.
469 *
470 * <p>
471 * It is common practise to create and return a single composite that
472 * contains the entire window contents.
473 * </p>
474 *
475 * <p>
476 * The default implementation of this framework method creates an instance
477 * of <code>Composite</code>. Subclasses may override.
478 * </p>
479 *
480 * @param parent
481 * the parent composite for the controls in this window. The type
482 * of layout used is determined by getLayout()
483 *
484 * @return the control that will be returned by subsequent calls to
485 * getContents()
486 */
487 protected Control createContents(Composite parent) {
488 // by default, just create a composite
489 return new Composite(parent, SWT.NONE);
490 }
491
492 /**
493 * Creates and returns this window's shell.
494 * <p>
495 * The default implementation of this framework method creates a new shell
496 * and configures it using <code/>configureShell</code>. Rather than
497 * override this method, subclasses should instead override
498 * <code/>configureShell</code>.
499 * </p>
500 *
501 * @return the shell
502 */
503 protected final Shell createShell() {
504
505 Shell newParent = getParentShell();
506 if(newParent !is null && newParent.isDisposed()){
507 parentShell = new SameShellProvider(null);
508 newParent = getParentShell();//Find a better parent
509 }
510
511 //Create the shell
512 Shell newShell = new Shell(newParent, getShellStyle());
513
514 resizeListener = new class Listener {
515 public void handleEvent(Event e) {
516 resizeHasOccurred = true;
517 }
518 };
519
520 newShell.addListener(SWT.Resize, resizeListener);
521 newShell.setData(this);
522
523 //Add a listener
524 newShell.addShellListener(getShellListener());
525
526 //Set the layout
527 configureShell(newShell);
528
529 //Register for font changes
530 if (fontChangeListener is null) {
531 fontChangeListener = new FontChangeListener();
532 }
533 JFaceResources.getFontRegistry().addListener(fontChangeListener);
534
535 return newShell;
536 }
537
538 /**
539 * Returns the top level control for this window. The parent of this control
540 * is the shell.
541 *
542 * @return the top level control, or <code>null</code> if this window's
543 * control has not been created yet
544 */
545 protected Control getContents() {
546 return contents;
547 }
548
549 /**
550 * Returns the default image. This is the image that will be used for
551 * windows that have no shell image at the time they are opened. There is no
552 * default image unless one is installed via <code>setDefaultImage</code>.
553 *
554 * @return the default image, or <code>null</code> if none
555 * @see #setDefaultImage
556 */
557 public static Image getDefaultImage() {
558 return (defaultImages is null || defaultImages.length < 1) ? null
559 : defaultImages[0];
560 }
561
562 /**
563 * Returns the array of default images to use for newly opened windows. It
564 * is expected that the array will contain the same icon rendered at
565 * different resolutions.
566 *
567 * @see org.eclipse.swt.widgets.Decorations#setImages(org.eclipse.swt.graphics.Image[])
568 *
569 * @return the array of images to be used when a new window is opened
570 * @see #setDefaultImages
571 * @since 3.0
572 */
573 public static Image[] getDefaultImages() {
574 return (defaultImages is null ? new Image[0] : defaultImages);
575 }
576
577 /**
578 * Returns the initial location to use for the shell. The default
579 * implementation centers the shell horizontally (1/2 of the difference to
580 * the left and 1/2 to the right) and vertically (1/3 above and 2/3 below)
581 * relative to the parent shell, or display bounds if there is no parent
582 * shell.
583 *
584 * @param initialSize
585 * the initial size of the shell, as returned by
586 * <code>getInitialSize</code>.
587 * @return the initial location of the shell
588 */
589 protected Point getInitialLocation(Point initialSize) {
590 Composite parent = shell.getParent();
591
592 org.eclipse.swt.widgets.Monitor.Monitor monitor = shell.getDisplay().getPrimaryMonitor();
593 if (parent !is null) {
594 monitor = parent.getMonitor();
595 }
596
597 Rectangle monitorBounds = monitor.getClientArea();
598 Point centerPoint;
599 if (parent !is null) {
600 centerPoint = Geometry.centerPoint(parent.getBounds());
601 } else {
602 centerPoint = Geometry.centerPoint(monitorBounds);
603 }
604
605 return new Point(centerPoint.x - (initialSize.x / 2), Math.max(
606 monitorBounds.y, Math.min(centerPoint.y
607 - (initialSize.y * 2 / 3), monitorBounds.y
608 + monitorBounds.height - initialSize.y)));
609 }
610
611 /**
612 * Returns the initial size to use for the shell. The default implementation
613 * returns the preferred size of the shell, using
614 * <code>Shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true)</code>.
615 *
616 * @return the initial size of the shell
617 */
618 protected Point getInitialSize() {
619 return shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
620 }
621
622 /**
623 * Returns the most specific modal child from the given list of Shells.
624 *
625 * @param toSearch shells to search for modal children
626 * @return the most specific modal child, or null if none
627 *
628 * @since 3.1
629 */
630 private static Shell getModalChild(Shell[] toSearch) {
631 int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL | SWT.PRIMARY_MODAL;
632
633 for (int i = toSearch.length - 1; i >= 0; i--) {
634 Shell shell = toSearch[i];
635
636 // Check if this shell has a modal child
637 Shell[] children = shell.getShells();
638 Shell modalChild = getModalChild(children);
639 if (modalChild !is null) {
640 return modalChild;
641 }
642
643 // If not, check if this shell is modal itself
644 if (shell.isVisible() && (shell.getStyle() & modal) !is 0) {
645 return shell;
646 }
647 }
648
649 return null;
650 }
651
652 /**
653 * Returns parent shell, under which this window's shell is created.
654 *
655 * @return the parent shell, or <code>null</code> if there is no parent
656 * shell
657 */
658 protected Shell getParentShell() {
659 Shell parent = parentShell.getShell();
660
661 int modal = SWT.APPLICATION_MODAL | SWT.SYSTEM_MODAL | SWT.PRIMARY_MODAL;
662
663 if ((getShellStyle() & modal) !is 0) {
664 // If this is a modal shell with no parent, pick a shell using defaultModalParent.
665 if (parent is null) {
666 parent = defaultModalParent.getShell();
667 }
668 }
669
670 return parent;
671 }
672
673 /**
674 * Returns this window's return code. A window's return codes are
675 * window-specific, although two standard return codes are predefined:
676 * <code>OK</code> and <code>CANCEL</code>.
677 *
678 * @return the return code
679 */
680 public int getReturnCode() {
681 return returnCode;
682 }
683
684 /**
685 * Returns this window's shell.
686 *
687 * @return this window's shell, or <code>null</code> if this window's
688 * shell has not been created yet
689 */
690 public Shell getShell() {
691 return shell;
692 }
693
694 /**
695 * Returns a shell listener. This shell listener gets registered with this
696 * window's shell.
697 * <p>
698 * The default implementation of this framework method returns a new
699 * listener that makes this window the active window for its window manager
700 * (if it has one) when the shell is activated, and calls the framework
701 * method <code>handleShellCloseEvent</code> when the shell is closed.
702 * Subclasses may extend or reimplement.
703 * </p>
704 *
705 * @return a shell listener
706 */
707 protected ShellListener getShellListener() {
708 return new class ShellAdapter {
709 public void shellClosed(ShellEvent event) {
710 event.doit = false; // don't close now
711 if (canHandleShellCloseEvent()) {
712 handleShellCloseEvent();
713 }
714 }
715 };
716 }
717
718 /**
719 * Returns the shell style bits.
720 * <p>
721 * The default value is <code>SWT.CLOSE|SWT.MIN|SWT.MAX|SWT.RESIZE</code>.
722 * Subclassers should call <code>setShellStyle</code> to change this
723 * value, rather than overriding this method.
724 * </p>
725 *
726 * @return the shell style bits
727 */
728 protected int getShellStyle() {
729 return shellStyle;
730 }
731
732 /**
733 * Returns the window manager of this window.
734 *
735 * @return the WindowManager, or <code>null</code> if none
736 */
737 public WindowManager getWindowManager() {
738 return windowManager;
739 }
740
741 /**
742 * Notifies of a font property change.
743 * <p>
744 * The default implementation of this framework method does nothing.
745 * Subclasses may reimplement.
746 * </p>
747 *
748 * @param event
749 * the property change event detailing what changed
750 */
751 protected void handleFontChange(PropertyChangeEvent event) {
752 // do nothing
753 }
754
755 /**
756 * Notifies that the window's close button was pressed, the close menu was
757 * selected, or the ESCAPE key pressed.
758 * <p>
759 * The default implementation of this framework method sets the window's
760 * return code to <code>CANCEL</code> and closes the window using
761 * <code>close</code>. Subclasses may extend or reimplement.
762 * </p>
763 */
764 protected void handleShellCloseEvent() {
765 setReturnCode(CANCEL);
766 close();
767 }
768
769 /**
770 * Initializes the location and size of this window's SWT shell after it has
771 * been created.
772 * <p>
773 * This framework method is called by the <code>create</code> framework
774 * method. The default implementation calls <code>getInitialSize</code>
775 * and <code>getInitialLocation</code> and passes the results to
776 * <code>Shell.setBounds</code>. This is only done if the bounds of the
777 * shell have not already been modified. Subclasses may extend or
778 * reimplement.
779 * </p>
780 */
781 protected void initializeBounds() {
782 if (resizeListener !is null) {
783 shell.removeListener(SWT.Resize, resizeListener);
784 }
785 if (resizeHasOccurred) { // Check if shell size has been set already.
786 return;
787 }
788
789 Point size = getInitialSize();
790 Point location = getInitialLocation(size);
791 shell.setBounds(getConstrainedShellBounds(new Rectangle(location.x,
792 location.y, size.x, size.y)));
793 }
794
795 /**
796 * Opens this window, creating it first if it has not yet been created.
797 * <p>
798 * If this window has been configured to block on open (
799 * <code>setBlockOnOpen</code>), this method waits until the window is
800 * closed by the end user, and then it returns the window's return code;
801 * otherwise, this method returns immediately. A window's return codes are
802 * window-specific, although two standard return codes are predefined:
803 * <code>OK</code> and <code>CANCEL</code>.
804 * </p>
805 *
806 * @return the return code
807 *
808 * @see #create()
809 */
810 public int open() {
811
812 if (shell is null || shell.isDisposed()) {
813 shell = null;
814 // create the window
815 create();
816 }
817
818 // limit the shell size to the display size
819 constrainShellSize();
820
821 // open the window
822 shell.open();
823
824 // run the event loop if specified
825 if (block) {
826 runEventLoop(shell);
827 }
828
829 return returnCode;
830 }
831
832 /**
833 * Runs the event loop for the given shell.
834 *
835 * @param loopShell
836 * the shell
837 */
838 private void runEventLoop(Shell loopShell) {
839
840 //Use the display provided by the shell if possible
841 Display display;
842 if (shell is null) {
843 display = Display.getCurrent();
844 } else {
845 display = loopShell.getDisplay();
846 }
847
848 while (loopShell !is null && !loopShell.isDisposed()) {
849 try {
850 if (!display.readAndDispatch()) {
851 display.sleep();
852 }
853 } catch (Exception e) {
854 exceptionHandler.handleException(e);
855 }
856 }
857 display.update();
858 }
859
860 /**
861 * Sets whether the <code>open</code> method should block until the window
862 * closes.
863 *
864 * @param shouldBlock
865 * <code>true</code> if the <code>open</code> method should
866 * not return until the window closes, and <code>false</code>
867 * if the <code>open</code> method should return immediately
868 */
869 public void setBlockOnOpen(bool shouldBlock) {
870 block = shouldBlock;
871 }
872
873 /**
874 * Sets the default image. This is the image that will be used for windows
875 * that have no shell image at the time they are opened. There is no default
876 * image unless one is installed via this method.
877 *
878 * @param image
879 * the default image, or <code>null</code> if none
880 */
881 public static void setDefaultImage(Image image) {
882 defaultImages = image is null ? null : [ image ];
883 }
884
885 /**
886 * Sets the array of default images to use for newly opened windows. It is
887 * expected that the array will contain the same icon rendered at different
888 * resolutions.
889 *
890 * @see org.eclipse.swt.widgets.Decorations#setImages(org.eclipse.swt.graphics.Image[])
891 *
892 * @param images
893 * the array of images to be used when this window is opened
894 * @since 3.0
895 */
896 public static void setDefaultImages(Image[] images) {
897 Image[] newArray = new Image[images.length];
898 System.arraycopy(images, 0, newArray, 0, newArray.length);
899 defaultImages = newArray;
900 }
901
902 /**
903 * Changes the parent shell. This is only safe to use when the shell is not
904 * yet realized (i.e., created). Once the shell is created, it must be
905 * disposed (i.e., closed) before this method can be called.
906 *
907 * @param newParentShell
908 * The new parent shell; this value may be <code>null</code> if
909 * there is to be no parent.
910 * @since 3.1
911 */
912 protected void setParentShell(Shell newParentShell) {
913 Assert.isTrue((shell is null), "There must not be an existing shell."); //$NON-NLS-1$
914 parentShell = new SameShellProvider(newParentShell);
915 }
916
917 /**
918 * Sets this window's return code. The return code is automatically returned
919 * by <code>open</code> if block on open is enabled. For non-blocking
920 * opens, the return code needs to be retrieved manually using
921 * <code>getReturnCode</code>.
922 *
923 * @param code
924 * the return code
925 */
926 protected void setReturnCode(int code) {
927 returnCode = code;
928 }
929
930 /**
931 * Returns the monitor whose client area contains the given point. If no
932 * monitor contains the point, returns the monitor that is closest to the
933 * point. If this is ever made public, it should be moved into a separate
934 * utility class.
935 *
936 * @param toSearch
937 * point to find (display coordinates)
938 * @param toFind
939 * point to find (display coordinates)
940 * @return the montor closest to the given point
941 */
942 private static org.eclipse.swt.widgets.Monitor.Monitor getClosestMonitor(Display toSearch, Point toFind) {
943 int closest = Integer.MAX_VALUE;
944
945 org.eclipse.swt.widgets.Monitor.Monitor[] monitors = toSearch.getMonitors();
946 org.eclipse.swt.widgets.Monitor.Monitor result = monitors[0];
947
948 for (int idx = 0; idx < monitors.length; idx++) {
949 org.eclipse.swt.widgets.Monitor.Monitor current = monitors[idx];
950
951 Rectangle clientArea = current.getClientArea();
952
953 if (clientArea.contains(toFind)) {
954 return current;
955 }
956
957 int distance = Geometry.distanceSquared(Geometry
958 .centerPoint(clientArea), toFind);
959 if (distance < closest) {
960 closest = distance;
961 result = current;
962 }
963 }
964
965 return result;
966 }
967
968 /**
969 * Given the desired position of the window, this method returns an adjusted
970 * position such that the window is no larger than its monitor, and does not
971 * extend beyond the edge of the monitor. This is used for computing the
972 * initial window position, and subclasses can use this as a utility method
973 * if they want to limit the region in which the window may be moved.
974 *
975 * @param preferredSize
976 * the preferred position of the window
977 * @return a rectangle as close as possible to preferredSize that does not
978 * extend outside the monitor
979 *
980 * @since 3.0
981 */
982 protected Rectangle getConstrainedShellBounds(Rectangle preferredSize) {
983 Rectangle result = new Rectangle(preferredSize.x, preferredSize.y,
984 preferredSize.width, preferredSize.height);
985
986 org.eclipse.swt.widgets.Monitor.Monitor mon = getClosestMonitor(getShell().getDisplay(), Geometry
987 .centerPoint(result));
988
989 Rectangle bounds = mon.getClientArea();
990
991 if (result.height > bounds.height) {
992 result.height = bounds.height;
993 }
994
995 if (result.width > bounds.width) {
996 result.width = bounds.width;
997 }
998
999 result.x = Math.max(bounds.x, Math.min(result.x, bounds.x
1000 + bounds.width - result.width));
1001 result.y = Math.max(bounds.y, Math.min(result.y, bounds.y
1002 + bounds.height - result.height));
1003
1004 return result;
1005 }
1006
1007 /**
1008 * Sets the shell style bits. This method has no effect after the shell is
1009 * created.
1010 * <p>
1011 * The shell style bits are used by the framework method
1012 * <code>createShell</code> when creating this window's shell.
1013 * </p>
1014 *
1015 * @param newShellStyle
1016 * the new shell style bits
1017 */
1018 protected void setShellStyle(int newShellStyle) {
1019 shellStyle = newShellStyle;
1020 }
1021
1022 /**
1023 * Sets the window manager of this window.
1024 * <p>
1025 * Note that this method is used by <code>WindowManager</code> to maintain
1026 * a backpointer. Clients must not call the method directly.
1027 * </p>
1028 *
1029 * @param manager
1030 * the window manager, or <code>null</code> if none
1031 */
1032 public void setWindowManager(WindowManager manager) {
1033 windowManager = manager;
1034
1035 // Code to detect invalid usage
1036
1037 if (manager !is null) {
1038 Window[] windows = manager.getWindows();
1039 for (int i = 0; i < windows.length; i++) {
1040 if (windows[i] is this) {
1041 return;
1042 }
1043 }
1044 manager.add(this);
1045 }
1046 }
1047
1048 /**
1049 * Sets the exception handler for this application.
1050 * <p>
1051 * Note that the handler may only be set once. Subsequent calls to this method will be
1052 * ignored.
1053 * <p>
1054 *
1055 * @param handler
1056 * the exception handler for the application.
1057 */
1058 public static void setExceptionHandler(IExceptionHandler handler) {
1059 if ( cast(DefaultExceptionHandler)exceptionHandler ) {
1060 exceptionHandler_ = handler;
1061 }
1062 }
1063
1064 /**
1065 * Sets the default parent for modal Windows. This will be used to locate
1066 * the parent for any modal Window constructed with a null parent.
1067 *
1068 * @param provider shell provider that will be used to locate the parent shell
1069 * whenever a Window is created with a null parent
1070 * @since 3.1
1071 */
1072 public static void setDefaultModalParent(IShellProvider provider) {
1073 defaultModalParent_ = provider;
1074 }
1075
1076 /**
1077 * Gets the default orientation for windows. If it is not
1078 * set the default value will be unspecified (SWT#NONE).
1079 *
1080 *
1081 * @return SWT#NONE, SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT
1082 * @see SWT#RIGHT_TO_LEFT
1083 * @see SWT#LEFT_TO_RIGHT
1084 * @see SWT#NONE
1085 * @since 3.1
1086 */
1087 public static int getDefaultOrientation() {
1088 return orientation;
1089
1090 }
1091
1092 /**
1093 * Sets the default orientation of windows.
1094 * @param defaultOrientation one of
1095 * SWT#RIGHT_TO_LEFT, SWT#LEFT_TO_RIGHT ,SWT#NONE
1096 * @see SWT#RIGHT_TO_LEFT
1097 * @see SWT#LEFT_TO_RIGHT
1098 * @see SWT#NONE
1099 * @since 3.1
1100 */
1101 public static void setDefaultOrientation(int defaultOrientation) {
1102 orientation = defaultOrientation;
1103
1104 }
1105
1106 }