1 /*
2 * Copyright 1995-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package java.awt;
26
27 import java.awt.peer.DialogPeer;
28 import java.awt.event;
29 import java.io.ObjectInputStream;
30 import java.io.IOException;
31 import java.util.Iterator;
32 import java.util.concurrent.atomic.AtomicLong;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35 import javax.accessibility;
36 import sun.awt.AppContext;
37 import sun.awt.SunToolkit;
38 import sun.awt.PeerEvent;
39 import sun.awt.util.IdentityArrayList;
40 import sun.awt.util.IdentityLinkedList;
41 import sun.security.util.SecurityConstants;
42
43 /**
44 * A Dialog is a top-level window with a title and a border
45 * that is typically used to take some form of input from the user.
46 *
47 * The size of the dialog includes any area designated for the
48 * border. The dimensions of the border area can be obtained
49 * using the <code>getInsets</code> method, however, since
50 * these dimensions are platform-dependent, a valid insets
51 * value cannot be obtained until the dialog is made displayable
52 * by either calling <code>pack</code> or <code>show</code>.
53 * Since the border area is included in the overall size of the
54 * dialog, the border effectively obscures a portion of the dialog,
55 * constraining the area available for rendering and/or displaying
56 * subcomponents to the rectangle which has an upper-left corner
57 * location of <code>(insets.left, insets.top)</code>, and has a size of
58 * <code>width - (insets.left + insets.right)</code> by
59 * <code>height - (insets.top + insets.bottom)</code>.
60 * <p>
61 * The default layout for a dialog is <code>BorderLayout</code>.
62 * <p>
63 * A dialog may have its native decorations (i.e. Frame & Titlebar) turned off
64 * with <code>setUndecorated</code>. This can only be done while the dialog
65 * is not {@link Component#isDisplayable() displayable}.
66 * <p>
67 * A dialog may have another window as its owner when it's constructed. When
68 * the owner window of a visible dialog is minimized, the dialog will
69 * automatically be hidden from the user. When the owner window is subsequently
70 * restored, the dialog is made visible to the user again.
71 * <p>
72 * In a multi-screen environment, you can create a <code>Dialog</code>
73 * on a different screen device than its owner. See {@link java.awt.Frame} for
74 * more information.
75 * <p>
76 * A dialog can be either modeless (the default) or modal. A modal
77 * dialog is one which blocks input to some other top-level windows
78 * in the application, except for any windows created with the dialog
79 * as their owner. See <a href="doc-files/Modality.html">AWT Modality</a>
80 * specification for details.
81 * <p>
82 * Dialogs are capable of generating the following
83 * <code>WindowEvents</code>:
84 * <code>WindowOpened</code>, <code>WindowClosing</code>,
85 * <code>WindowClosed</code>, <code>WindowActivated</code>,
86 * <code>WindowDeactivated</code>, <code>WindowGainedFocus</code>,
87 * <code>WindowLostFocus</code>.
88 *
89 * @see WindowEvent
90 * @see Window#addWindowListener
91 *
92 * @author Sami Shaio
93 * @author Arthur van Hoff
94 * @since JDK1.0
95 */
96 public class Dialog extends Window {
97
98 static {
99 /* ensure that the necessary native libraries are loaded */
100 Toolkit.loadLibraries();
101 if (!GraphicsEnvironment.isHeadless()) {
102 initIDs();
103 }
104 }
105
106 /**
107 * A dialog's resizable property. Will be true
108 * if the Dialog is to be resizable, otherwise
109 * it will be false.
110 *
111 * @serial
112 * @see #setResizable(boolean)
113 */
114 boolean resizable = true;
115
116
117 /**
118 * This field indicates whether the dialog is undecorated.
119 * This property can only be changed while the dialog is not displayable.
120 * <code>undecorated</code> will be true if the dialog is
121 * undecorated, otherwise it will be false.
122 *
123 * @serial
124 * @see #setUndecorated(boolean)
125 * @see #isUndecorated()
126 * @see Component#isDisplayable()
127 * @since 1.4
128 */
129 boolean undecorated = false;
130
131 /**
132 * Modal dialogs block all input to some top-level windows.
133 * Whether a particular window is blocked depends on dialog's type
134 * of modality; this is called the "scope of blocking". The
135 * <code>ModalityType</code> enum specifies modal types and their
136 * associated scopes.
137 *
138 * @see Dialog#getModalityType
139 * @see Dialog#setModalityType
140 * @see Toolkit#isModalityTypeSupported
141 *
142 * @since 1.6
143 */
144 public static enum ModalityType {
145 /**
146 * <code>MODELESS</code> dialog doesn't block any top-level windows.
147 */
148 MODELESS,
149 /**
150 * A <code>DOCUMENT_MODAL</code> dialog blocks input to all top-level windows
151 * from the same document except those from its own child hierarchy.
152 * A document is a top-level window without an owner. It may contain child
153 * windows that, together with the top-level window are treated as a single
154 * solid document. Since every top-level window must belong to some
155 * document, its root can be found as the top-nearest window without an owner.
156 */
157 DOCUMENT_MODAL,
158 /**
159 * An <code>APPLICATION_MODAL</code> dialog blocks all top-level windows
160 * from the same Java application except those from its own child hierarchy.
161 * If there are several applets launched in a browser, they can be
162 * treated either as separate applications or a single one. This behavior
163 * is implementation-dependent.
164 */
165 APPLICATION_MODAL,
166 /**
167 * A <code>TOOLKIT_MODAL</code> dialog blocks all top-level windows run
168 * from the same toolkit except those from its own child hierarchy. If there
169 * are several applets launched in a browser, all of them run with the same
170 * toolkit; thus, a toolkit-modal dialog displayed by an applet may affect
171 * other applets and all windows of the browser instance which embeds the
172 * Java runtime environment for this toolkit.
173 * Special <code>AWTPermission</code> "toolkitModality" must be granted to use
174 * toolkit-modal dialogs. If a <code>TOOLKIT_MODAL</code> dialog is being created
175 * and this permission is not granted, a <code>SecurityException</code> will be
176 * thrown, and no dialog will be created. If a modality type is being changed
177 * to <code>TOOLKIT_MODAL</code> and this permission is not granted, a
178 * <code>SecurityException</code> will be thrown, and the modality type will
179 * be left unchanged.
180 */
181 TOOLKIT_MODAL
182 };
183
184 /**
185 * Default modality type for modal dialogs. The default modality type is
186 * <code>APPLICATION_MODAL</code>. Calling the oldstyle <code>setModal(true)</code>
187 * is equal to <code>setModalityType(DEFAULT_MODALITY_TYPE)</code>.
188 *
189 * @see java.awt.Dialog.ModalityType
190 * @see java.awt.Dialog#setModal
191 *
192 * @since 1.6
193 */
194 public final static ModalityType DEFAULT_MODALITY_TYPE = ModalityType.APPLICATION_MODAL;
195
196 /**
197 * True if this dialog is modal, false is the dialog is modeless.
198 * A modal dialog blocks user input to some application top-level
199 * windows. This field is kept only for backwards compatibility. Use the
200 * {@link Dialog.ModalityType ModalityType} enum instead.
201 *
202 * @serial
203 *
204 * @see #isModal
205 * @see #setModal
206 * @see #getModalityType
207 * @see #setModalityType
208 * @see ModalityType
209 * @see ModalityType#MODELESS
210 * @see #DEFAULT_MODALITY_TYPE
211 */
212 boolean modal;
213
214 /**
215 * Modality type of this dialog. If the dialog's modality type is not
216 * {@link Dialog.ModalityType#MODELESS ModalityType.MODELESS}, it blocks all
217 * user input to some application top-level windows.
218 *
219 * @serial
220 *
221 * @see ModalityType
222 * @see #getModalityType
223 * @see #setModalityType
224 *
225 * @since 1.6
226 */
227 ModalityType modalityType;
228
229 /**
230 * Any top-level window can be marked not to be blocked by modal
231 * dialogs. This is called "modal exclusion". This enum specifies
232 * the possible modal exclusion types.
233 *
234 * @see Window#getModalExclusionType
235 * @see Window#setModalExclusionType
236 * @see Toolkit#isModalExclusionTypeSupported
237 *
238 * @since 1.6
239 */
240 public static enum ModalExclusionType {
241 /**
242 * No modal exclusion.
243 */
244 NO_EXCLUDE,
245 /**
246 * <code>APPLICATION_EXCLUDE</code> indicates that a top-level window
247 * won't be blocked by any application-modal dialogs. Also, it isn't
248 * blocked by document-modal dialogs from outside of its child hierarchy.
249 */
250 APPLICATION_EXCLUDE,
251 /**
252 * <code>TOOLKIT_EXCLUDE</code> indicates that a top-level window
253 * won't be blocked by application-modal or toolkit-modal dialogs. Also,
254 * it isn't blocked by document-modal dialogs from outside of its
255 * child hierarchy.
256 * The "toolkitModality" <code>AWTPermission</code> must be granted
257 * for this exclusion. If an exclusion property is being changed to
258 * <code>TOOLKIT_EXCLUDE</code> and this permission is not granted, a
259 * <code>SecurityEcxeption</code> will be thrown, and the exclusion
260 * property will be left unchanged.
261 */
262 TOOLKIT_EXCLUDE
263 };
264
265 /**
266 * @since 1.6
267 */
268 private final static ModalExclusionType DEFAULT_MODAL_EXCLUSION_TYPE =
269 ModalExclusionType.APPLICATION_EXCLUDE;
270
271 /* operations with this list should be synchronized on tree lock*/
272 transient static IdentityArrayList<Dialog> modalDialogs = new IdentityArrayList<Dialog>();
273
274 transient IdentityArrayList<Window> blockedWindows = new IdentityArrayList<Window>();
275
276 /**
277 * Specifies the title of the Dialog.
278 * This field can be null.
279 *
280 * @serial
281 * @see #getTitle()
282 * @see #setTitle(String)
283 */
284 String title;
285
286 private transient volatile boolean keepBlockingEDT = false;
287 private transient volatile boolean keepBlockingCT = false;
288
289 private transient ModalEventFilter modalFilter;
290
291 /*
292 * Indicates that this dialog is being hidden. This flag is set to true at
293 * the beginning of hide() and to false at the end of hide().
294 *
295 * @see #hide()
296 * @see #hideAndDisposePreHandler()
297 * @see #hideAndDisposeHandler()
298 * @see #shouldBlock()
299 */
300 transient volatile boolean isInHide = false;
301
302 /*
303 * Indicates that this dialog is being disposed. This flag is set to true at
304 * the beginning of doDispose() and to false at the end of doDispose().
305 *
306 * @see #hide()
307 * @see #hideAndDisposePreHandler()
308 * @see #hideAndDisposeHandler()
309 * @see #doDispose()
310 */
311 transient volatile boolean isInDispose = false;
312
313 private static final String base = "dialog";
314 private static int nameCounter = 0;
315
316 /*
317 * JDK 1.1 serialVersionUID
318 */
319 private static final long serialVersionUID = 5920926903803293709L;
320
321 /**
322 * Constructs an initially invisible, modeless <code>Dialog</code> with
323 * the specified owner <code>Frame</code> and an empty title.
324 *
325 * @param owner the owner of the dialog or <code>null</code> if
326 * this dialog has no owner
327 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
328 * <code>GraphicsConfiguration</code> is not from a screen device
329 * @exception HeadlessException when
330 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
331 *
332 * @see java.awt.GraphicsEnvironment#isHeadless
333 * @see Component#setSize
334 * @see Component#setVisible
335 */
336 public Dialog(Frame owner) {
337 this(owner, "", false);
338 }
339
340 /**
341 * Constructs an initially invisible <code>Dialog</code> with the specified
342 * owner <code>Frame</code> and modality and an empty title.
343 *
344 * @param owner the owner of the dialog or <code>null</code> if
345 * this dialog has no owner
346 * @param modal specifes whether dialog blocks user input to other top-level
347 * windows when shown. If <code>false</code>, the dialog is <code>MODELESS</code>;
348 * if <code>true</code>, the modality type property is set to
349 * <code>DEFAULT_MODALITY_TYPE</code>
350 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
351 * <code>GraphicsConfiguration</code> is not from a screen device
352 * @exception HeadlessException when
353 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
354 *
355 * @see java.awt.Dialog.ModalityType
356 * @see java.awt.Dialog.ModalityType#MODELESS
357 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
358 * @see java.awt.Dialog#setModal
359 * @see java.awt.Dialog#setModalityType
360 * @see java.awt.GraphicsEnvironment#isHeadless
361 */
362 public Dialog(Frame owner, boolean modal) {
363 this(owner, "", modal);
364 }
365
366 /**
367 * Constructs an initially invisible, modeless <code>Dialog</code> with
368 * the specified owner <code>Frame</code> and title.
369 *
370 * @param owner the owner of the dialog or <code>null</code> if
371 * this dialog has no owner
372 * @param title the title of the dialog or <code>null</code> if this dialog
373 * has no title
374 * @exception IllegalArgumentException if the <code>owner</code>'s
375 * <code>GraphicsConfiguration</code> is not from a screen device
376 * @exception HeadlessException when
377 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
378 *
379 * @see java.awt.GraphicsEnvironment#isHeadless
380 * @see Component#setSize
381 * @see Component#setVisible
382 */
383 public Dialog(Frame owner, String title) {
384 this(owner, title, false);
385 }
386
387 /**
388 * Constructs an initially invisible <code>Dialog</code> with the
389 * specified owner <code>Frame</code>, title and modality.
390 *
391 * @param owner the owner of the dialog or <code>null</code> if
392 * this dialog has no owner
393 * @param title the title of the dialog or <code>null</code> if this dialog
394 * has no title
395 * @param modal specifes whether dialog blocks user input to other top-level
396 * windows when shown. If <code>false</code>, the dialog is <code>MODELESS</code>;
397 * if <code>true</code>, the modality type property is set to
398 * <code>DEFAULT_MODALITY_TYPE</code>
399 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
400 * <code>GraphicsConfiguration</code> is not from a screen device
401 * @exception HeadlessException when
402 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
403 *
404 * @see java.awt.Dialog.ModalityType
405 * @see java.awt.Dialog.ModalityType#MODELESS
406 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
407 * @see java.awt.Dialog#setModal
408 * @see java.awt.Dialog#setModalityType
409 * @see java.awt.GraphicsEnvironment#isHeadless
410 * @see Component#setSize
411 * @see Component#setVisible
412 */
413 public Dialog(Frame owner, String title, boolean modal) {
414 this(owner, title, modal ? DEFAULT_MODALITY_TYPE : ModalityType.MODELESS);
415 }
416
417 /**
418 * Constructs an initially invisible <code>Dialog</code> with the specified owner
419 * <code>Frame</code>, title, modality, and <code>GraphicsConfiguration</code>.
420 * @param owner the owner of the dialog or <code>null</code> if this dialog
421 * has no owner
422 * @param title the title of the dialog or <code>null</code> if this dialog
423 * has no title
424 * @param modal specifes whether dialog blocks user input to other top-level
425 * windows when shown. If <code>false</code>, the dialog is <code>MODELESS</code>;
426 * if <code>true</code>, the modality type property is set to
427 * <code>DEFAULT_MODALITY_TYPE</code>
428 * @param gc the <code>GraphicsConfiguration</code> of the target screen device;
429 * if <code>null</code>, the default system <code>GraphicsConfiguration</code>
430 * is assumed
431 * @exception java.lang.IllegalArgumentException if <code>gc</code>
432 * is not from a screen device
433 * @exception HeadlessException when
434 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
435 *
436 * @see java.awt.Dialog.ModalityType
437 * @see java.awt.Dialog.ModalityType#MODELESS
438 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
439 * @see java.awt.Dialog#setModal
440 * @see java.awt.Dialog#setModalityType
441 * @see java.awt.GraphicsEnvironment#isHeadless
442 * @see Component#setSize
443 * @see Component#setVisible
444 * @since 1.4
445 */
446 public Dialog(Frame owner, String title, boolean modal,
447 GraphicsConfiguration gc) {
448 this(owner, title, modal ? DEFAULT_MODALITY_TYPE : ModalityType.MODELESS, gc);
449 }
450
451 /**
452 * Constructs an initially invisible, modeless <code>Dialog</code> with
453 * the specified owner <code>Dialog</code> and an empty title.
454 *
455 * @param owner the owner of the dialog or <code>null</code> if this
456 * dialog has no owner
457 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
458 * <code>GraphicsConfiguration</code> is not from a screen device
459 * @exception HeadlessException when
460 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
461 * @see java.awt.GraphicsEnvironment#isHeadless
462 * @since 1.2
463 */
464 public Dialog(Dialog owner) {
465 this(owner, "", false);
466 }
467
468 /**
469 * Constructs an initially invisible, modeless <code>Dialog</code>
470 * with the specified owner <code>Dialog</code> and title.
471 *
472 * @param owner the owner of the dialog or <code>null</code> if this
473 * has no owner
474 * @param title the title of the dialog or <code>null</code> if this dialog
475 * has no title
476 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
477 * <code>GraphicsConfiguration</code> is not from a screen device
478 * @exception HeadlessException when
479 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
480 *
481 * @see java.awt.GraphicsEnvironment#isHeadless
482 * @since 1.2
483 */
484 public Dialog(Dialog owner, String title) {
485 this(owner, title, false);
486 }
487
488 /**
489 * Constructs an initially invisible <code>Dialog</code> with the
490 * specified owner <code>Dialog</code>, title, and modality.
491 *
492 * @param owner the owner of the dialog or <code>null</code> if this
493 * dialog has no owner
494 * @param title the title of the dialog or <code>null</code> if this
495 * dialog has no title
496 * @param modal specifes whether dialog blocks user input to other top-level
497 * windows when shown. If <code>false</code>, the dialog is <code>MODELESS</code>;
498 * if <code>true</code>, the modality type property is set to
499 * <code>DEFAULT_MODALITY_TYPE</code>
500 * @exception IllegalArgumentException if the <code>owner</code>'s
501 * <code>GraphicsConfiguration</code> is not from a screen device
502 * @exception HeadlessException when
503 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
504 *
505 * @see java.awt.Dialog.ModalityType
506 * @see java.awt.Dialog.ModalityType#MODELESS
507 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
508 * @see java.awt.Dialog#setModal
509 * @see java.awt.Dialog#setModalityType
510 * @see java.awt.GraphicsEnvironment#isHeadless
511 *
512 * @since 1.2
513 */
514 public Dialog(Dialog owner, String title, boolean modal) {
515 this(owner, title, modal ? DEFAULT_MODALITY_TYPE : ModalityType.MODELESS);
516 }
517
518 /**
519 * Constructs an initially invisible <code>Dialog</code> with the
520 * specified owner <code>Dialog</code>, title, modality and
521 * <code>GraphicsConfiguration</code>.
522 *
523 * @param owner the owner of the dialog or <code>null</code> if this
524 * dialog has no owner
525 * @param title the title of the dialog or <code>null</code> if this
526 * dialog has no title
527 * @param modal specifes whether dialog blocks user input to other top-level
528 * windows when shown. If <code>false</code>, the dialog is <code>MODELESS</code>;
529 * if <code>true</code>, the modality type property is set to
530 * <code>DEFAULT_MODALITY_TYPE</code>
531 * @param gc the <code>GraphicsConfiguration</code> of the target screen device;
532 * if <code>null</code>, the default system <code>GraphicsConfiguration</code>
533 * is assumed
534 * @exception java.lang.IllegalArgumentException if <code>gc</code>
535 * is not from a screen device
536 * @exception HeadlessException when
537 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
538 *
539 * @see java.awt.Dialog.ModalityType
540 * @see java.awt.Dialog.ModalityType#MODELESS
541 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
542 * @see java.awt.Dialog#setModal
543 * @see java.awt.Dialog#setModalityType
544 * @see java.awt.GraphicsEnvironment#isHeadless
545 * @see Component#setSize
546 * @see Component#setVisible
547 *
548 * @since 1.4
549 */
550 public Dialog(Dialog owner, String title, boolean modal,
551 GraphicsConfiguration gc) {
552 this(owner, title, modal ? DEFAULT_MODALITY_TYPE : ModalityType.MODELESS, gc);
553 }
554
555 /**
556 * Constructs an initially invisible, modeless <code>Dialog</code> with the
557 * specified owner <code>Window</code> and an empty title.
558 *
559 * @param owner the owner of the dialog. The owner must be an instance of
560 * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any
561 * of their descendents or <code>null</code>
562 *
563 * @exception java.lang.IllegalArgumentException if the <code>owner</code>
564 * is not an instance of {@link java.awt.Dialog Dialog} or {@link
565 * java.awt.Frame Frame}
566 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
567 * <code>GraphicsConfiguration</code> is not from a screen device
568 * @exception HeadlessException when
569 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
570 *
571 * @see java.awt.GraphicsEnvironment#isHeadless
572 *
573 * @since 1.6
574 */
575 public Dialog(Window owner) {
576 this(owner, null, ModalityType.MODELESS);
577 }
578
579 /**
580 * Constructs an initially invisible, modeless <code>Dialog</code> with
581 * the specified owner <code>Window</code> and title.
582 *
583 * @param owner the owner of the dialog. The owner must be an instance of
584 * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any
585 * of their descendents or <code>null</code>
586 * @param title the title of the dialog or <code>null</code> if this dialog
587 * has no title
588 *
589 * @exception java.lang.IllegalArgumentException if the <code>owner</code>
590 * is not an instance of {@link java.awt.Dialog Dialog} or {@link
591 * java.awt.Frame Frame}
592 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
593 * <code>GraphicsConfiguration</code> is not from a screen device
594 * @exception HeadlessException when
595 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
596 *
597 * @see java.awt.GraphicsEnvironment#isHeadless
598 *
599 * @since 1.6
600 */
601 public Dialog(Window owner, String title) {
602 this(owner, title, ModalityType.MODELESS);
603 }
604
605 /**
606 * Constructs an initially invisible <code>Dialog</code> with the
607 * specified owner <code>Window</code> and modality and an empty title.
608 *
609 * @param owner the owner of the dialog. The owner must be an instance of
610 * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any
611 * of their descendents or <code>null</code>
612 * @param modalityType specifies whether dialog blocks input to other
613 * windows when shown. <code>null</code> value and unsupported modality
614 * types are equivalent to <code>MODELESS</code>
615 *
616 * @exception java.lang.IllegalArgumentException if the <code>owner</code>
617 * is not an instance of {@link java.awt.Dialog Dialog} or {@link
618 * java.awt.Frame Frame}
619 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
620 * <code>GraphicsConfiguration</code> is not from a screen device
621 * @exception HeadlessException when
622 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
623 * @exception SecurityException if the calling thread does not have permission
624 * to create modal dialogs with the given <code>modalityType</code>
625 *
626 * @see java.awt.Dialog.ModalityType
627 * @see java.awt.Dialog#setModal
628 * @see java.awt.Dialog#setModalityType
629 * @see java.awt.GraphicsEnvironment#isHeadless
630 * @see java.awt.Toolkit#isModalityTypeSupported
631 *
632 * @since 1.6
633 */
634 public Dialog(Window owner, ModalityType modalityType) {
635 this(owner, null, modalityType);
636 }
637
638 /**
639 * Constructs an initially invisible <code>Dialog</code> with the
640 * specified owner <code>Window</code>, title and modality.
641 *
642 * @param owner the owner of the dialog. The owner must be an instance of
643 * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any
644 * of their descendents or <code>null</code>
645 * @param title the title of the dialog or <code>null</code> if this dialog
646 * has no title
647 * @param modalityType specifies whether dialog blocks input to other
648 * windows when shown. <code>null</code> value and unsupported modality
649 * types are equivalent to <code>MODELESS</code>
650 *
651 * @exception java.lang.IllegalArgumentException if the <code>owner</code>
652 * is not an instance of {@link java.awt.Dialog Dialog} or {@link
653 * java.awt.Frame Frame}
654 * @exception java.lang.IllegalArgumentException if the <code>owner</code>'s
655 * <code>GraphicsConfiguration</code> is not from a screen device
656 * @exception HeadlessException when
657 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
658 * @exception SecurityException if the calling thread does not have permission
659 * to create modal dialogs with the given <code>modalityType</code>
660 *
661 * @see java.awt.Dialog.ModalityType
662 * @see java.awt.Dialog#setModal
663 * @see java.awt.Dialog#setModalityType
664 * @see java.awt.GraphicsEnvironment#isHeadless
665 * @see java.awt.Toolkit#isModalityTypeSupported
666 *
667 * @since 1.6
668 */
669 public Dialog(Window owner, String title, ModalityType modalityType) {
670 super(owner);
671
672 if ((owner != null) &&
673 !(owner instanceof Frame) &&
674 !(owner instanceof Dialog))
675 {
676 throw new IllegalArgumentException("Wrong parent window");
677 }
678
679 this.title = title;
680 setModalityType(modalityType);
681 SunToolkit.checkAndSetPolicy(this, false);
682 }
683
684 /**
685 * Constructs an initially invisible <code>Dialog</code> with the
686 * specified owner <code>Window</code>, title, modality and
687 * <code>GraphicsConfiguration</code>.
688 *
689 * @param owner the owner of the dialog. The owner must be an instance of
690 * {@link java.awt.Dialog Dialog}, {@link java.awt.Frame Frame}, any
691 * of their descendents or <code>null</code>
692 * @param title the title of the dialog or <code>null</code> if this dialog
693 * has no title
694 * @param modalityType specifies whether dialog blocks input to other
695 * windows when shown. <code>null</code> value and unsupported modality
696 * types are equivalent to <code>MODELESS</code>
697 * @param gc the <code>GraphicsConfiguration</code> of the target screen device;
698 * if <code>null</code>, the default system <code>GraphicsConfiguration</code>
699 * is assumed
700 *
701 * @exception java.lang.IllegalArgumentException if the <code>owner</code>
702 * is not an instance of {@link java.awt.Dialog Dialog} or {@link
703 * java.awt.Frame Frame}
704 * @exception java.lang.IllegalArgumentException if <code>gc</code>
705 * is not from a screen device
706 * @exception HeadlessException when
707 * <code>GraphicsEnvironment.isHeadless()</code> returns <code>true</code>
708 * @exception SecurityException if the calling thread does not have permission
709 * to create modal dialogs with the given <code>modalityType</code>
710 *
711 * @see java.awt.Dialog.ModalityType
712 * @see java.awt.Dialog#setModal
713 * @see java.awt.Dialog#setModalityType
714 * @see java.awt.GraphicsEnvironment#isHeadless
715 * @see java.awt.Toolkit#isModalityTypeSupported
716 *
717 * @since 1.6
718 */
719 public Dialog(Window owner, String title, ModalityType modalityType,
720 GraphicsConfiguration gc) {
721 super(owner, gc);
722
723 if ((owner != null) &&
724 !(owner instanceof Frame) &&
725 !(owner instanceof Dialog))
726 {
727 throw new IllegalArgumentException("wrong owner window");
728 }
729
730 this.title = title;
731 setModalityType(modalityType);
732 SunToolkit.checkAndSetPolicy(this, false);
733 }
734
735 /**
736 * Construct a name for this component. Called by getName() when the
737 * name is null.
738 */
739 String constructComponentName() {
740 synchronized (Dialog.class) {
741 return base + nameCounter++;
742 }
743 }
744
745 /**
746 * Makes this Dialog displayable by connecting it to
747 * a native screen resource. Making a dialog displayable will
748 * cause any of its children to be made displayable.
749 * This method is called internally by the toolkit and should
750 * not be called directly by programs.
751 * @see Component#isDisplayable
752 * @see #removeNotify
753 */
754 public void addNotify() {
755 synchronized (getTreeLock()) {
756 if (parent != null && parent.getPeer() == null) {
757 parent.addNotify();
758 }
759
760 if (peer == null) {
761 peer = getToolkit().createDialog(this);
762 }
763 super.addNotify();
764 }
765 }
766
767 /**
768 * Indicates whether the dialog is modal.
769 * <p>
770 * This method is obsolete and is kept for backwards compatiblity only.
771 * Use {@link #getModalityType getModalityType()} instead.
772 *
773 * @return <code>true</code> if this dialog window is modal;
774 * <code>false</code> otherwise
775 *
776 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
777 * @see java.awt.Dialog.ModalityType#MODELESS
778 * @see java.awt.Dialog#setModal
779 * @see java.awt.Dialog#getModalityType
780 * @see java.awt.Dialog#setModalityType
781 */
782 public boolean isModal() {
783 return isModal_NoClientCode();
784 }
785 final boolean isModal_NoClientCode() {
786 return modalityType != ModalityType.MODELESS;
787 }
788
789 /**
790 * Specifies whether this dialog should be modal.
791 * <p>
792 * This method is obsolete and is kept for backwards compatibility only.
793 * Use {@link #setModalityType setModalityType()} instead.
794 * <p>
795 * Note: changing modality of the visible dialog may have no effect
796 * until it is hidden and then shown again.
797 *
798 * @param modal specifies whether dialog blocks input to other windows
799 * when shown; calling to <code>setModal(true)</code> is equivalent to
800 * <code>setModalityType(Dialog.DEFAULT_MODALITY_TYPE)</code>, and
801 * calling to <code>setModal(false)</code> is equvivalent to
802 * <code>setModalityType(Dialog.ModalityType.MODELESS)</code>
803 *
804 * @see java.awt.Dialog#DEFAULT_MODALITY_TYPE
805 * @see java.awt.Dialog.ModalityType#MODELESS
806 * @see java.awt.Dialog#isModal
807 * @see java.awt.Dialog#getModalityType
808 * @see java.awt.Dialog#setModalityType
809 *
810 * @since 1.1
811 */
812 public void setModal(boolean modal) {
813 this.modal = modal;
814 setModalityType(modal ? DEFAULT_MODALITY_TYPE : ModalityType.MODELESS);
815 }
816
817 /**
818 * Returns the modality type of this dialog.
819 *
820 * @return modality type of this dialog
821 *
822 * @see java.awt.Dialog#setModalityType
823 *
824 * @since 1.6
825 */
826 public ModalityType getModalityType() {
827 return modalityType;
828 }
829
830 /**
831 * Sets the modality type for this dialog. See {@link
832 * java.awt.Dialog.ModalityType ModalityType} for possible modality types.
833 * <p>
834 * If the given modality type is not supported, <code>MODELESS</code>
835 * is used. You may want to call <code>getModalityType()</code> after calling
836 * this method to ensure that the modality type has been set.
837 * <p>
838 * Note: changing modality of the visible dialog may have no effect
839 * until it is hidden and then shown again.
840 *
841 * @param type specifies whether dialog blocks input to other
842 * windows when shown. <code>null</code> value and unsupported modality
843 * types are equivalent to <code>MODELESS</code>
844 * @exception SecurityException if the calling thread does not have permission
845 * to create modal dialogs with the given <code>modalityType</code>
846 *
847 * @see java.awt.Dialog#getModalityType
848 * @see java.awt.Toolkit#isModalityTypeSupported
849 *
850 * @since 1.6
851 */
852 public void setModalityType(ModalityType type) {
853 if (type == null) {
854 type = Dialog.ModalityType.MODELESS;
855 }
856 if (!Toolkit.getDefaultToolkit().isModalityTypeSupported(type)) {
857 type = Dialog.ModalityType.MODELESS;
858 }
859 if (modalityType == type) {
860 return;
861 }
862 if (type == ModalityType.TOOLKIT_MODAL) {
863 SecurityManager sm = System.getSecurityManager();
864 if (sm != null) {
865 sm.checkPermission(SecurityConstants.TOOLKIT_MODALITY_PERMISSION);
866 }
867 }
868 modalityType = type;
869 modal = (modalityType != ModalityType.MODELESS);
870 }
871
872 /**
873 * Gets the title of the dialog. The title is displayed in the
874 * dialog's border.
875 * @return the title of this dialog window. The title may be
876 * <code>null</code>.
877 * @see java.awt.Dialog#setTitle
878 */
879 public String getTitle() {
880 return title;
881 }
882
883 /**
884 * Sets the title of the Dialog.
885 * @param title the title displayed in the dialog's border;
886 * a null value results in an empty title
887 * @see #getTitle
888 */
889 public void setTitle(String title) {
890 String oldTitle = this.title;
891
892 synchronized(this) {
893 this.title = title;
894 DialogPeer peer = (DialogPeer)this.peer;
895 if (peer != null) {
896 peer.setTitle(title);
897 }
898 }
899 firePropertyChange("title", oldTitle, title);
900 }
901
902 /**
903 * @return true if we actually showed, false if we just called toFront()
904 */
905 private boolean conditionalShow(Component toFocus, AtomicLong time) {
906 boolean retval;
907
908 closeSplashScreen();
909
910 synchronized (getTreeLock()) {
911 if (peer == null) {
912 addNotify();
913 }
914 validate();
915 if (visible) {
916 toFront();
917 retval = false;
918 } else {
919 visible = retval = true;
920
921 // check if this dialog should be modal blocked BEFORE calling peer.show(),
922 // otherwise, a pair of FOCUS_GAINED and FOCUS_LOST may be mistakenly
923 // generated for the dialog
924 if (!isModal()) {
925 checkShouldBeBlocked(this);
926 } else {
927 modalDialogs.add(this);
928 modalShow();
929 }
930
931 if (toFocus != null && time != null && isFocusable() &&
932 isEnabled() && !isModalBlocked()) {
933 // keep the KeyEvents from being dispatched
934 // until the focus has been transfered
935 time.set(Toolkit.getEventQueue().getMostRecentEventTimeEx());
936 KeyboardFocusManager.getCurrentKeyboardFocusManager().
937 enqueueKeyEvents(time.get(), toFocus);
938 }
939
940 // This call is required as the show() method of the Dialog class
941 // does not invoke the super.show(). So wried... :(
942 mixOnShowing();
943
944 peer.show(); // now guaranteed never to block
945 if (isModalBlocked()) {
946 modalBlocker.toFront();
947 }
948
949 setLocationByPlatform(false);
950 for (int i = 0; i < ownedWindowList.size(); i++) {
951 Window child = ownedWindowList.elementAt(i).get();
952 if ((child != null) && child.showWithParent) {
953 child.show();
954 child.showWithParent = false;
955 } // endif
956 } // endfor
957 Window.updateChildFocusableWindowState(this);
958
959 createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED,
960 this, parent,
961 HierarchyEvent.SHOWING_CHANGED,
962 Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK));
963 if (componentListener != null ||
964 (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 ||
965 Toolkit.enabledOnToolkit(AWTEvent.COMPONENT_EVENT_MASK)) {
966 ComponentEvent e =
967 new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN);
968 Toolkit.getEventQueue().postEvent(e);
969 }
970 }
971 }
972
973 if (retval && (state & OPENED) == 0) {
974 postWindowEvent(WindowEvent.WINDOW_OPENED);
975 state |= OPENED;
976 }
977
978 return retval;
979 }
980
981 /**
982 * Shows or hides this {@code Dialog} depending on the value of parameter
983 * {@code b}.
984 * @param b if {@code true}, makes the {@code Dialog} visible,
985 * otherwise hides the {@code Dialog}.
986 * If the dialog and/or its owner
987 * are not yet displayable, both are made displayable. The
988 * dialog will be validated prior to being made visible.
989 * If {@code false}, hides the {@code Dialog} and then causes {@code setVisible(true)}
990 * to return if it is currently blocked.
991 * <p>
992 * <b>Notes for modal dialogs</b>.
993 * <ul>
994 * <li>{@code setVisible(true)}: If the dialog is not already
995 * visible, this call will not return until the dialog is
996 * hidden by calling {@code setVisible(false)} or
997 * {@code dispose}.
998 * <li>{@code setVisible(false)}: Hides the dialog and then
999 * returns on {@code setVisible(true)} if it is currently blocked.
1000 * <li>It is OK to call this method from the event dispatching
1001 * thread because the toolkit ensures that other events are
1002 * not blocked while this method is blocked.
1003 * </ul>
1004 * @see java.awt.Window#setVisible
1005 * @see java.awt.Window#dispose
1006 * @see java.awt.Component#isDisplayable
1007 * @see java.awt.Component#validate
1008 * @see java.awt.Dialog#isModal
1009 */
1010 public void setVisible(boolean b) {
1011 super.setVisible(b);
1012 }
1013
1014 /**
1015 * Stores the app context on which event dispatch thread the dialog
1016 * is being shown. Initialized in show(), used in hideAndDisposeHandler()
1017 */
1018 transient private AppContext showAppContext;
1019
1020 /**
1021 * Makes the {@code Dialog} visible. If the dialog and/or its owner
1022 * are not yet displayable, both are made displayable. The
1023 * dialog will be validated prior to being made visible.
1024 * If the dialog is already visible, this will bring the dialog
1025 * to the front.
1026 * <p>
1027 * If the dialog is modal and is not already visible, this call
1028 * will not return until the dialog is hidden by calling hide or
1029 * dispose. It is permissible to show modal dialogs from the event
1030 * dispatching thread because the toolkit will ensure that another
1031 * event pump runs while the one which invoked this method is blocked.
1032 * @see Component#hide
1033 * @see Component#isDisplayable
1034 * @see Component#validate
1035 * @see #isModal
1036 * @see Window#setVisible(boolean)
1037 * @deprecated As of JDK version 1.5, replaced by
1038 * {@link #setVisible(boolean) setVisible(boolean)}.
1039 */
1040 @Deprecated
1041 public void show() {
1042 beforeFirstShow = false;
1043 if (!isModal()) {
1044 conditionalShow(null, null);
1045 } else {
1046 // Set this variable before calling conditionalShow(). That
1047 // way, if the Dialog is hidden right after being shown, we
1048 // won't mistakenly block this thread.
1049 keepBlockingEDT = true;
1050 keepBlockingCT = true;
1051
1052 // Store the app context on which this dialog is being shown.
1053 // Event dispatch thread of this app context will be sleeping until
1054 // we wake it by any event from hideAndDisposeHandler().
1055 showAppContext = AppContext.getAppContext();
1056
1057 AtomicLong time = new AtomicLong();
1058 Component predictedFocusOwner = null;
1059 try {
1060 predictedFocusOwner = getMostRecentFocusOwner();
1061 if (conditionalShow(predictedFocusOwner, time)) {
1062 // We have two mechanisms for blocking: 1. If we're on the
1063 // EventDispatchThread, start a new event pump. 2. If we're
1064 // on any other thread, call wait() on the treelock.
1065
1066 modalFilter = ModalEventFilter.createFilterForDialog(this);
1067
1068 final Runnable pumpEventsForFilter = new Runnable() {
1069 public void run() {
1070 EventDispatchThread dispatchThread =
1071 (EventDispatchThread)Thread.currentThread();
1072 dispatchThread.pumpEventsForFilter(new Conditional() {
1073 public boolean evaluate() {
1074 synchronized (getTreeLock()) {
1075 return keepBlockingEDT && windowClosingException == null;
1076 }
1077 }
1078 }, modalFilter);
1079 }
1080 };
1081
1082 // if this dialog is toolkit-modal, the filter should be added
1083 // to all EDTs (for all AppContexts)
1084 if (modalityType == ModalityType.TOOLKIT_MODAL) {
1085 Iterator it = AppContext.getAppContexts().iterator();
1086 while (it.hasNext()) {
1087 AppContext appContext = (AppContext)it.next();
1088 if (appContext == showAppContext) {
1089 continue;
1090 }
1091 EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
1092 // it may occur that EDT for appContext hasn't been started yet, so
1093 // we post an empty invocation event to trigger EDT initialization
1094 Runnable createEDT = new Runnable() {
1095 public void run() {};
1096 };
1097 eventQueue.postEvent(new InvocationEvent(this, createEDT));
1098 EventDispatchThread edt = eventQueue.getDispatchThread();
1099 edt.addEventFilter(modalFilter);
1100 }
1101 }
1102
1103 modalityPushed();
1104 try {
1105 if (EventQueue.isDispatchThread()) {
1106 /*
1107 * dispose SequencedEvent we are dispatching on current
1108 * AppContext, to prevent us from hang.
1109 *
1110 */
1111 // BugId 4531693 (son@sparc.spb.su)
1112 SequencedEvent currentSequencedEvent = KeyboardFocusManager.
1113 getCurrentKeyboardFocusManager().getCurrentSequencedEvent();
1114 if (currentSequencedEvent != null) {
1115 currentSequencedEvent.dispose();
1116 }
1117
1118 /*
1119 * Event processing is done inside doPrivileged block so that
1120 * it wouldn't matter even if user code is on the stack
1121 * Fix for BugId 6300270
1122 */
1123
1124 AccessController.doPrivileged(new PrivilegedAction() {
1125 public Object run() {
1126 pumpEventsForFilter.run();
1127 return null;
1128 }
1129 });
1130 } else {
1131 synchronized (getTreeLock()) {
1132 Toolkit.getEventQueue().postEvent(new PeerEvent(this,
1133 pumpEventsForFilter,
1134 PeerEvent.PRIORITY_EVENT));
1135 while (keepBlockingCT && windowClosingException == null) {
1136 try {
1137 getTreeLock().wait();
1138 } catch (InterruptedException e) {
1139 break;
1140 }
1141 }
1142 }
1143 }
1144 } finally {
1145 modalityPopped();
1146 }
1147
1148 // if this dialog is toolkit-modal, its filter must be removed
1149 // from all EDTs (for all AppContexts)
1150 if (modalityType == ModalityType.TOOLKIT_MODAL) {
1151 Iterator it = AppContext.getAppContexts().iterator();
1152 while (it.hasNext()) {
1153 AppContext appContext = (AppContext)it.next();
1154 if (appContext == showAppContext) {
1155 continue;
1156 }
1157 EventQueue eventQueue = (EventQueue)appContext.get(AppContext.EVENT_QUEUE_KEY);
1158 EventDispatchThread edt = eventQueue.getDispatchThread();
1159 edt.removeEventFilter(modalFilter);
1160 }
1161 }
1162
1163 if (windowClosingException != null) {
1164 windowClosingException.fillInStackTrace();
1165 throw windowClosingException;
1166 }
1167 }
1168 } finally {
1169 if (predictedFocusOwner != null) {
1170 // Restore normal key event dispatching
1171 KeyboardFocusManager.getCurrentKeyboardFocusManager().
1172 dequeueKeyEvents(time.get(), predictedFocusOwner);
1173 }
1174 }
1175 }
1176 }
1177
1178 final void modalityPushed() {
1179 Toolkit tk = Toolkit.getDefaultToolkit();
1180 if (tk instanceof SunToolkit) {
1181 SunToolkit stk = (SunToolkit)tk;
1182 stk.notifyModalityPushed(this);
1183 }
1184 }
1185
1186 final void modalityPopped() {
1187 Toolkit tk = Toolkit.getDefaultToolkit();
1188 if (tk instanceof SunToolkit) {
1189 SunToolkit stk = (SunToolkit)tk;
1190 stk.notifyModalityPopped(this);
1191 }
1192 }
1193
1194 void interruptBlocking() {
1195 if (isModal()) {
1196 disposeImpl();
1197 } else if (windowClosingException != null) {
1198 windowClosingException.fillInStackTrace();
1199 windowClosingException.printStackTrace();
1200 windowClosingException = null;
1201 }
1202 }
1203 final class WakingRunnable implements Runnable {
1204 public void run() {
1205 synchronized (getTreeLock()) {
1206 keepBlockingCT = false;
1207 getTreeLock().notifyAll();
1208 }
1209 }
1210 }
1211 private void hideAndDisposePreHandler() {
1212 isInHide = true;
1213 synchronized (getTreeLock()) {
1214 if (keepBlockingEDT) {
1215 modalHide();
1216 // dialog can be shown and then disposed before its
1217 // modal filter is created
1218 if (modalFilter != null) {
1219 modalFilter.disable();
1220 }
1221 modalDialogs.remove(this);
1222 }
1223 }
1224 }
1225 private void hideAndDisposeHandler() {
1226 synchronized (getTreeLock()) {
1227 if (keepBlockingEDT) {
1228 keepBlockingEDT = false;
1229 PeerEvent wakingEvent = new PeerEvent(this, new WakingRunnable(), PeerEvent.PRIORITY_EVENT);
1230 AppContext curAppContext = AppContext.getAppContext();
1231 if (showAppContext != curAppContext) {
1232 // Wake up event dispatch thread on which the dialog was
1233 // initially shown
1234 SunToolkit.postEvent(showAppContext, wakingEvent);
1235 showAppContext = null;
1236 } else {
1237 Toolkit.getEventQueue().postEvent(wakingEvent);
1238 }
1239 }
1240 }
1241 isInHide = false;
1242 }
1243
1244 /**
1245 * Hides the Dialog and then causes {@code show} to return if it is currently
1246 * blocked.
1247 * @see Window#show
1248 * @see Window#dispose
1249 * @see Window#setVisible(boolean)
1250 * @deprecated As of JDK version 1.5, replaced by
1251 * {@link #setVisible(boolean) setVisible(boolean)}.
1252 */
1253 @Deprecated
1254 public void hide() {
1255 hideAndDisposePreHandler();
1256 super.hide();
1257 // fix for 5048370: if hide() is called from super.doDispose(), then
1258 // hideAndDisposeHandler() should not be called here as it will be called
1259 // at the end of doDispose()
1260 if (!isInDispose) {
1261 hideAndDisposeHandler();
1262 }
1263 }
1264
1265 /**
1266 * Disposes the Dialog and then causes show() to return if it is currently
1267 * blocked.
1268 */
1269 void doDispose() {
1270 // fix for 5048370: set isInDispose flag to true to prevent calling
1271 // to hideAndDisposeHandler() from hide()
1272 isInDispose = true;
1273 super.doDispose();
1274 hideAndDisposeHandler();
1275 isInDispose = false;
1276 }
1277
1278 /**
1279 * {@inheritDoc}
1280 * <p>
1281 * If this dialog is modal and blocks some windows, then all of them are
1282 * also sent to the back to keep them below the blocking dialog.
1283 *
1284 * @see java.awt.Window#toBack
1285 */
1286 public void toBack() {
1287 super.toBack();
1288 if (visible) {
1289 synchronized (getTreeLock()) {
1290 for (Window w : blockedWindows) {
1291 w.toBack_NoClientCode();
1292 }
1293 }
1294 }
1295 }
1296
1297 /**
1298 * Indicates whether this dialog is resizable by the user.
1299 * By default, all dialogs are initially resizable.
1300 * @return <code>true</code> if the user can resize the dialog;
1301 * <code>false</code> otherwise.
1302 * @see java.awt.Dialog#setResizable
1303 */
1304 public boolean isResizable() {
1305 return resizable;
1306 }
1307
1308 /**
1309 * Sets whether this dialog is resizable by the user.
1310 * @param resizable <code>true</code> if the user can
1311 * resize this dialog; <code>false</code> otherwise.
1312 * @see java.awt.Dialog#isResizable
1313 */
1314 public void setResizable(boolean resizable) {
1315 boolean testvalid = false;
1316
1317 synchronized (this) {
1318 this.resizable = resizable;
1319 DialogPeer peer = (DialogPeer)this.peer;
1320 if (peer != null) {
1321 peer.setResizable(resizable);
1322 testvalid = true;
1323 }
1324 }
1325
1326 // On some platforms, changing the resizable state affects
1327 // the insets of the Dialog. If we could, we'd call invalidate()
1328 // from the peer, but we need to guarantee that we're not holding
1329 // the Dialog lock when we call invalidate().
1330 if (testvalid && valid) {
1331 invalidate();
1332 }
1333 }
1334
1335
1336 /**
1337 * Disables or enables decorations for this dialog.
1338 * This method can only be called while the dialog is not displayable.
1339 * @param undecorated <code>true</code> if no dialog decorations are
1340 * to be enabled;
1341 * <code>false</code> if dialog decorations are to be enabled.
1342 * @throws <code>IllegalComponentStateException</code> if the dialog
1343 * is displayable.
1344 * @see #isUndecorated
1345 * @see Component#isDisplayable
1346 * @since 1.4
1347 */
1348 public void setUndecorated(boolean undecorated) {
1349 /* Make sure we don't run in the middle of peer creation.*/
1350 synchronized (getTreeLock()) {
1351 if (isDisplayable()) {
1352 throw new IllegalComponentStateException("The dialog is displayable.");
1353 }
1354 this.undecorated = undecorated;
1355 }
1356 }
1357
1358 /**
1359 * Indicates whether this dialog is undecorated.
1360 * By default, all dialogs are initially decorated.
1361 * @return <code>true</code> if dialog is undecorated;
1362 * <code>false</code> otherwise.
1363 * @see java.awt.Dialog#setUndecorated
1364 * @since 1.4
1365 */
1366 public boolean isUndecorated() {
1367 return undecorated;
1368 }
1369
1370 /**
1371 * Returns a string representing the state of this dialog. This
1372 * method is intended to be used only for debugging purposes, and the
1373 * content and format of the returned string may vary between
1374 * implementations. The returned string may be empty but may not be
1375 * <code>null</code>.
1376 *
1377 * @return the parameter string of this dialog window.
1378 */
1379 protected String paramString() {
1380 String str = super.paramString() + "," + modalityType;
1381 if (title != null) {
1382 str += ",title=" + title;
1383 }
1384 return str;
1385 }
1386
1387 /**
1388 * Initialize JNI field and method IDs
1389 */
1390 private static native void initIDs();
1391
1392 /*
1393 * --- Modality support ---
1394 *
1395 */
1396
1397 /*
1398 * This method is called only for modal dialogs.
1399 *
1400 * Goes through the list of all visible top-level windows and
1401 * divide them into three distinct groups: blockers of this dialog,
1402 * blocked by this dialog and all others. Then blocks this dialog
1403 * by first met dialog from the first group (if any) and blocks all
1404 * the windows from the second group.
1405 */
1406 void modalShow() {
1407 // find all the dialogs that block this one
1408 IdentityArrayList<Dialog> blockers = new IdentityArrayList<Dialog>();
1409 for (Dialog d : modalDialogs) {
1410 if (d.shouldBlock(this)) {
1411 Window w = d;
1412 while ((w != null) && (w != this)) {
1413 w = (Window)(w.getOwner_NoClientCode());
1414 }
1415 if ((w == this) || !shouldBlock(d) || (modalityType.compareTo(d.getModalityType()) < 0)) {
1416 blockers.add(d);
1417 }
1418 }
1419 }
1420
1421 // add all blockers' blockers to blockers :)
1422 for (int i = 0; i < blockers.size(); i++) {
1423 Dialog blocker = blockers.get(i);
1424 if (blocker.isModalBlocked()) {
1425 Dialog blockerBlocker = blocker.getModalBlocker();
1426 if (!blockers.contains(blockerBlocker)) {
1427 blockers.add(i + 1, blockerBlocker);
1428 }
1429 }
1430 }
1431
1432 if (blockers.size() > 0) {
1433 blockers.get(0).blockWindow(this);
1434 }
1435
1436 // find all windows from blockers' hierarchies
1437 IdentityArrayList<Window> blockersHierarchies = new IdentityArrayList<Window>(blockers);
1438 int k = 0;
1439 while (k < blockersHierarchies.size()) {
1440 Window w = blockersHierarchies.get(k);
1441 Window[] ownedWindows = w.getOwnedWindows_NoClientCode();
1442 for (Window win : ownedWindows) {
1443 blockersHierarchies.add(win);
1444 }
1445 k++;
1446 }
1447
1448 java.util.List<Window> toBlock = new IdentityLinkedList<Window>();
1449 // block all windows from scope of blocking except from blockers' hierarchies
1450 IdentityArrayList<Window> unblockedWindows = Window.getAllUnblockedWindows();
1451 for (Window w : unblockedWindows) {
1452 if (shouldBlock(w) && !blockersHierarchies.contains(w)) {
1453 if ((w instanceof Dialog) && ((Dialog)w).isModal_NoClientCode()) {
1454 Dialog wd = (Dialog)w;
1455 if (wd.shouldBlock(this) && (modalDialogs.indexOf(wd) > modalDialogs.indexOf(this))) {
1456 continue;
1457 }
1458 }
1459 toBlock.add(w);
1460 }
1461 }
1462 blockWindows(toBlock);
1463
1464 if (!isModalBlocked()) {
1465 updateChildrenBlocking();
1466 }
1467 }
1468
1469 /*
1470 * This method is called only for modal dialogs.
1471 *
1472 * Unblocks all the windows blocked by this modal dialog. After
1473 * each of them has been unblocked, it is checked to be blocked by
1474 * any other modal dialogs.
1475 */
1476 void modalHide() {
1477 // we should unblock all the windows first...
1478 IdentityArrayList<Window> save = new IdentityArrayList<Window>();
1479 int blockedWindowsCount = blockedWindows.size();
1480 for (int i = 0; i < blockedWindowsCount; i++) {
1481 Window w = blockedWindows.get(0);
1482 save.add(w);
1483 unblockWindow(w); // also removes w from blockedWindows
1484 }
1485 // ... and only after that check if they should be blocked
1486 // by another dialogs
1487 for (int i = 0; i < blockedWindowsCount; i++) {
1488 Window w = save.get(i);
1489 if ((w instanceof Dialog) && ((Dialog)w).isModal_NoClientCode()) {
1490 Dialog d = (Dialog)w;
1491 d.modalShow();
1492 } else {
1493 checkShouldBeBlocked(w);
1494 }
1495 }
1496 }
1497
1498 /*
1499 * Returns whether the given top-level window should be blocked by
1500 * this dialog. Note, that the given window can be also a modal dialog
1501 * and it should block this dialog, but this method do not take such
1502 * situations into consideration (such checks are performed in the
1503 * modalShow() and modalHide() methods).
1504 *
1505 * This method should be called on the getTreeLock() lock.
1506 */
1507 boolean shouldBlock(Window w) {
1508 if (!isVisible_NoClientCode() ||
1509 (!w.isVisible_NoClientCode() && !w.isInShow) ||
1510 isInHide ||
1511 (w == this) ||
1512 !isModal_NoClientCode())
1513 {
1514 return false;
1515 }
1516 if ((w instanceof Dialog) && ((Dialog)w).isInHide) {
1517 return false;
1518 }
1519 // check if w is from children hierarchy
1520 // fix for 6271546: we should also take into consideration child hierarchies
1521 // of this dialog's blockers
1522 Window blockerToCheck = this;
1523 while (blockerToCheck != null) {
1524 Component c = w;
1525 while ((c != null) && (c != blockerToCheck)) {
1526 c = c.getParent_NoClientCode();
1527 }
1528 if (c == blockerToCheck) {
1529 return false;
1530 }
1531 blockerToCheck = blockerToCheck.getModalBlocker();
1532 }
1533 switch (modalityType) {
1534 case MODELESS:
1535 return false;
1536 case DOCUMENT_MODAL:
1537 if (w.isModalExcluded(ModalExclusionType.APPLICATION_EXCLUDE)) {
1538 // application- and toolkit-excluded windows are not blocked by
1539 // document-modal dialogs from outside their children hierarchy
1540 Component c = this;
1541 while ((c != null) && (c != w)) {
1542 c = c.getParent_NoClientCode();
1543 }
1544 return c == w;
1545 } else {
1546 return getDocumentRoot() == w.getDocumentRoot();
1547 }
1548 case APPLICATION_MODAL:
1549 return !w.isModalExcluded(ModalExclusionType.APPLICATION_EXCLUDE) &&
1550 (appContext == w.appContext);
1551 case TOOLKIT_MODAL:
1552 return !w.isModalExcluded(ModalExclusionType.TOOLKIT_EXCLUDE);
1553 }
1554
1555 return false;
1556 }
1557
1558 /*
1559 * Adds the given top-level window to the list of blocked
1560 * windows for this dialog and marks it as modal blocked.
1561 * If the window is already blocked by some modal dialog,
1562 * does nothing.
1563 */
1564 void blockWindow(Window w) {
1565 if (!w.isModalBlocked()) {
1566 w.setModalBlocked(this, true, true);
1567 blockedWindows.add(w);
1568 }
1569 }
1570
1571 void blockWindows(java.util.List<Window> toBlock) {
1572 DialogPeer dpeer = (DialogPeer)peer;
1573 if (dpeer == null) {
1574 return;
1575 }
1576 Iterator<Window> it = toBlock.iterator();
1577 while (it.hasNext()) {
1578 Window w = it.next();
1579 if (!w.isModalBlocked()) {
1580 w.setModalBlocked(this, true, false);
1581 } else {
1582 it.remove();
1583 }
1584 }
1585 dpeer.blockWindows(toBlock);
1586 blockedWindows.addAll(toBlock);
1587 }
1588
1589 /*
1590 * Removes the given top-level window from the list of blocked
1591 * windows for this dialog and marks it as unblocked. If the
1592 * window is not modal blocked, does nothing.
1593 */
1594 void unblockWindow(Window w) {
1595 if (w.isModalBlocked() && blockedWindows.contains(w)) {
1596 blockedWindows.remove(w);
1597 w.setModalBlocked(this, false, true);
1598 }
1599 }
1600
1601 /*
1602 * Checks if any other modal dialog D blocks the given window.
1603 * If such D exists, mark the window as blocked by D.
1604 */
1605 static void checkShouldBeBlocked(Window w) {
1606 synchronized (w.getTreeLock()) {
1607 for (int i = 0; i < modalDialogs.size(); i++) {
1608 Dialog modalDialog = modalDialogs.get(i);
1609 if (modalDialog.shouldBlock(w)) {
1610 modalDialog.blockWindow(w);
1611 break;
1612 }
1613 }
1614 }
1615 }
1616
1617 private void readObject(ObjectInputStream s)
1618 throws ClassNotFoundException, IOException, HeadlessException
1619 {
1620 GraphicsEnvironment.checkHeadless();
1621 s.defaultReadObject();
1622
1623 // in 1.5 or earlier modalityType was absent, so use "modal" instead
1624 if (modalityType == null) {
1625 setModal(modal);
1626 }
1627
1628 blockedWindows = new IdentityArrayList();
1629 }
1630
1631 /*
1632 * --- Accessibility Support ---
1633 *
1634 */
1635
1636 /**
1637 * Gets the AccessibleContext associated with this Dialog.
1638 * For dialogs, the AccessibleContext takes the form of an
1639 * AccessibleAWTDialog.
1640 * A new AccessibleAWTDialog instance is created if necessary.
1641 *
1642 * @return an AccessibleAWTDialog that serves as the
1643 * AccessibleContext of this Dialog
1644 * @since 1.3
1645 */
1646 public AccessibleContext getAccessibleContext() {
1647 if (accessibleContext == null) {
1648 accessibleContext = new AccessibleAWTDialog();
1649 }
1650 return accessibleContext;
1651 }
1652
1653 /**
1654 * This class implements accessibility support for the
1655 * <code>Dialog</code> class. It provides an implementation of the
1656 * Java Accessibility API appropriate to dialog user-interface elements.
1657 * @since 1.3
1658 */
1659 protected class AccessibleAWTDialog extends AccessibleAWTWindow
1660 {
1661 /*
1662 * JDK 1.3 serialVersionUID
1663 */
1664 private static final long serialVersionUID = 4837230331833941201L;
1665
1666 /**
1667 * Get the role of this object.
1668 *
1669 * @return an instance of AccessibleRole describing the role of the
1670 * object
1671 * @see AccessibleRole
1672 */
1673 public AccessibleRole getAccessibleRole() {
1674 return AccessibleRole.DIALOG;
1675 }
1676
1677 /**
1678 * Get the state of this object.
1679 *
1680 * @return an instance of AccessibleStateSet containing the current
1681 * state set of the object
1682 * @see AccessibleState
1683 */
1684 public AccessibleStateSet getAccessibleStateSet() {
1685 AccessibleStateSet states = super.getAccessibleStateSet();
1686 if (getFocusOwner() != null) {
1687 states.add(AccessibleState.ACTIVE);
1688 }
1689 if (isModal()) {
1690 states.add(AccessibleState.MODAL);
1691 }
1692 if (isResizable()) {
1693 states.add(AccessibleState.RESIZABLE);
1694 }
1695 return states;
1696 }
1697
1698 } // inner class AccessibleAWTDialog
1699 }