001    /* Dialog.java -- An AWT dialog box
002     Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006  
003     Free Software Foundation, Inc.
004    
005     This file is part of GNU Classpath.
006    
007     GNU Classpath is free software; you can redistribute it and/or modify
008     it under the terms of the GNU General Public License as published by
009     the Free Software Foundation; either version 2, or (at your option)
010     any later version.
011    
012     GNU Classpath is distributed in the hope that it will be useful, but
013     WITHOUT ANY WARRANTY; without even the implied warranty of
014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015     General Public License for more details.
016    
017     You should have received a copy of the GNU General Public License
018     along with GNU Classpath; see the file COPYING.  If not, write to the
019     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
020     02110-1301 USA.
021    
022     Linking this library statically or dynamically with other modules is
023     making a combined work based on this library.  Thus, the terms and
024     conditions of the GNU General Public License cover the whole
025     combination.
026    
027     As a special exception, the copyright holders of this library give you
028     permission to link this library with independent modules to produce an
029     executable, regardless of the license terms of these independent
030     modules, and to copy and distribute the resulting executable under
031     terms of your choice, provided that you also meet, for each linked
032     independent module, the terms and conditions of the license of that
033     module.  An independent module is a module which is not derived from
034     or based on this library.  If you modify this library, you may extend
035     this exception to your version of the library, but you are not
036     obligated to do so.  If you do not wish to do so, delete this
037     exception statement from your version. */
038    
039    
040    package java.awt;
041    
042    import java.awt.peer.DialogPeer;
043    
044    import javax.accessibility.AccessibleContext;
045    import javax.accessibility.AccessibleRole;
046    import javax.accessibility.AccessibleState;
047    import javax.accessibility.AccessibleStateSet;
048    
049    /**
050     * <code>Dialog</code> provides a top-level window normally used to receive 
051     * user input in applications.
052     * <p>
053     * A dialog always has another top-level window as owner and is only visible
054     * if this owner is visible to the user. The default layout of dialogs is the 
055     * <code>BorderLayout</code>. Dialogs can be modal (blocks user input to other
056     * components) or non-modal (user input in other components are allowed).
057     * </p> 
058     * 
059     * @author Aaron M. Renn (arenn@urbanophile.com)
060     * @author Tom Tromey (tromey@redhat.com)
061     */
062    public class Dialog extends Window
063    {
064      public enum ModalExclusionType
065      {
066        APPLICATION_EXCLUDE,
067        NO_EXCLUDE,
068        TOOLKIT_EXCLUDE
069      }
070    
071      public enum ModalityType
072      {
073        APPLICATION_MODAL,
074        DOCUMENT_MODAL,
075        MODELESS,
076        TOOLKIT_MODAL
077      }
078    
079      // Serialization constant
080      private static final long serialVersionUID = 5920926903803293709L;
081    
082      /**
083       * @serial Indicates whether or not this dialog box is modal.
084       */
085      private boolean modal;
086    
087      /**
088       * @serial Indicates whether or not this dialog box is resizable.
089       */
090      private boolean resizable = true;
091    
092      /**
093       * @serial The title string for this dialog box, which can be
094       *         <code>null</code>.
095       */
096      private String title;
097    
098      /**
099       * This field indicates whether the dialog is undecorated or not.
100       */
101      private boolean undecorated = false;
102    
103      /**
104       * Indicates that we are blocked for modality in show
105       */
106      private boolean blocked = false;
107    
108      /**
109       * Secondary EventQueue to handle AWT events while we are blocked for 
110       * modality in show.
111       */
112      private EventQueue eq2 = null;
113    
114      /**
115       * The number used to generate the name returned by getName.
116       */
117      private static transient long next_dialog_number;
118    
119      /**
120       * Initializes a new instance of <code>Dialog</code> with the specified
121       * parent, that is resizable and not modal, and which has no title.
122       * 
123       * @param parent The parent frame of this dialog box.
124       * @exception IllegalArgumentException If the owner's GraphicsConfiguration 
125       * is not from a screen device, or if owner is null. This exception is 
126       * always thrown when GraphicsEnvironment.isHeadless() returns true.
127       */
128      public Dialog(Frame parent)
129      {
130        this(parent, "", false);
131      }
132    
133      /**
134       * Initializes a new instance of <code>Dialog</code> with the specified
135       * parent and modality, that is resizable and which has no title.
136       * 
137       * @param parent The parent frame of this dialog box.
138       * @param modal <code>true</code> if this dialog box is modal,
139       * <code>false</code> otherwise.
140       * 
141       * @exception IllegalArgumentException If the owner's GraphicsConfiguration
142       * is not from a screen device, or if owner is null. This exception is 
143       * always thrown when GraphicsEnvironment.isHeadless() returns true.
144       */
145      public Dialog(Frame parent, boolean modal)
146      {
147        this(parent, "", modal);
148      }
149    
150      /**
151       * Initializes a new instance of <code>Dialog</code> with the specified
152       * parent, that is resizable and not modal, and which has the specified 
153       * title.
154       * 
155       * @param parent The parent frame of this dialog box.
156       * @param title The title string for this dialog box.
157       * 
158       * @exception IllegalArgumentException If the owner's GraphicsConfiguration
159       * is not from a screen device, or if owner is null. This exceptionnis 
160       * always thrown when GraphicsEnvironment.isHeadless() returns true.
161       */
162      public Dialog(Frame parent, String title)
163      {
164        this(parent, title, false);
165      }
166    
167      /**
168       * Initializes a new instance of <code>Dialog</code> with the specified,
169       * parent, title, and modality, that is resizable.
170       * 
171       * @param parent The parent frame of this dialog box.
172       * @param title The title string for this dialog box.
173       * @param modal <code>true</code> if this dialog box is modal,
174       * <code>false</code> otherwise.
175       *          
176       * @exception IllegalArgumentException If owner is null or
177       *              GraphicsEnvironment.isHeadless() returns true.
178       */
179      public Dialog(Frame parent, String title, boolean modal)
180      {
181        this(parent, title, modal, parent.getGraphicsConfiguration());
182      }
183    
184      /**
185       * Initializes a new instance of <code>Dialog</code> with the specified,
186       * parent, title, modality and <code>GraphicsConfiguration</code>, that is
187       * resizable.
188       * 
189       * @param parent The parent frame of this dialog box.
190       * @param title The title string for this dialog box.
191       * @param modal <code>true</code> if this dialog box is modal,
192       * <code>false</code> otherwise.
193       * @param gc The <code>GraphicsConfiguration</code> object to use. If 
194       * <code>null</code> the <code>GraphicsConfiguration</code> of the target 
195       * frame is used.
196       * 
197       * @exception IllegalArgumentException If owner is null, the
198       *              GraphicsConfiguration is not a screen device or
199       *              GraphicsEnvironment.isHeadless() returns true.
200       * @since 1.4
201       */
202      public Dialog(Frame parent, String title, boolean modal,
203                    GraphicsConfiguration gc)
204      {
205        super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc);
206    
207        // A null title is equivalent to an empty title
208        this.title = (title != null) ? title : "";
209        this.modal = modal;
210        visible = false;
211    
212        setLayout(new BorderLayout());
213        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
214      }
215    
216      /**
217       * Initializes a new instance of <code>Dialog</code> with the specified,
218       * parent, that is resizable.
219       * 
220       * @param owner The parent frame of this dialog box.
221       * 
222       * @exception IllegalArgumentException If parent is null. This exception is
223       * always thrown when GraphicsEnvironment.isHeadless() returns true.
224       * 
225       * @since 1.2
226       */
227      public Dialog(Dialog owner)
228      {
229        this(owner, "", false, owner.getGraphicsConfiguration());
230      }
231    
232      /**
233       * Initializes a new instance of <code>Dialog</code> with the specified,
234       * parent and title, that is resizable.
235       * 
236       * @param owner The parent frame of this dialog box.
237       * @param title The title string for this dialog box.
238       * 
239       * @exception IllegalArgumentException If parent is null. This exception is
240       *              always thrown when GraphicsEnvironment.isHeadless() returns
241       *              true.
242       * @since 1.2
243       */
244      public Dialog(Dialog owner, String title)
245      {
246        this(owner, title, false, owner.getGraphicsConfiguration());
247      }
248    
249      /**
250       * Initializes a new instance of <code>Dialog</code> with the specified,
251       * parent, title and modality, that is resizable.
252       * 
253       * @param owner The parent frame of this dialog box.
254       * @param title The title string for this dialog box.
255       * @param modal <code>true</code> if this dialog box is modal,
256       * <code>false</code> otherwise.
257       * 
258       * @exception IllegalArgumentException If parent is null. This exception is
259       * always thrown when GraphicsEnvironment.isHeadless() returns true.
260       * @since 1.2
261       */
262      public Dialog(Dialog owner, String title, boolean modal)
263      {
264        this(owner, title, modal, owner.getGraphicsConfiguration());
265      }
266    
267      /**
268       * Initializes a new instance of <code>Dialog</code> with the specified,
269       * parent, title, modality and <code>GraphicsConfiguration</code>, that is
270       * resizable.
271       * 
272       * @param parent The parent frame of this dialog box.
273       * @param title The title string for this dialog box.
274       * @param modal <code>true</code> if this dialog box is modal,
275       * <code>false</code> otherwise.
276       * @param gc The <code>GraphicsConfiguration</code> object to use. If 
277       * <code>null</code> the <code>GraphicsConfiguration</code> of the target 
278       * frame is used.
279       * 
280       * @exception IllegalArgumentException If parent is null, the
281       * GraphicsConfiguration is not a screen device or 
282       * GraphicsEnvironment.isHeadless() returns true.
283       * 
284       * @since 1.4
285       */
286      public Dialog(Dialog parent, String title, boolean modal,
287                    GraphicsConfiguration gc)
288      {
289        super(parent, (gc == null) ? parent.getGraphicsConfiguration() : gc);
290    
291        // A null title is equivalent to an empty title
292        this.title = (title != null) ? title : "";
293        this.modal = modal;
294        visible = false;
295    
296        setLayout(new BorderLayout());
297        setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
298      }
299    
300      /**
301       * Returns the title of this dialog box.
302       * 
303       * @return The title of this dialog box.
304       */
305      public String getTitle()
306      {
307        return title;
308      }
309    
310      /**
311       * Sets the title of this dialog box to the specified string.
312       * 
313       * @param title the new title. If <code>null</code> an empty
314       * title will be set.
315       */
316      public synchronized void setTitle(String title)
317      {
318        // A null title is equivalent to an empty title
319        this.title = (title != null) ? title : "";
320    
321        if (peer != null)
322          {
323            DialogPeer d = (DialogPeer) peer;
324            d.setTitle(title);
325          }
326      }
327    
328      /**
329       * Tests whether or not this dialog box is modal.
330       * 
331       * @return <code>true</code> if this dialog box is modal, <code>false</code>
332       * otherwise.
333       */
334      public boolean isModal()
335      {
336        return modal;
337      }
338    
339      /**
340       * Changes the modality of this dialog box. This can only be done before the
341       * peer is created.
342       * 
343       * @param modal <code>true</code> to make this dialog box modal,
344       * <code>false</code> to make it non-modal. 
345       */
346      public void setModal(boolean modal)
347      {
348        this.modal = modal;
349      }
350    
351      /**
352       * Tests whether or not this dialog box is resizable.
353       * 
354       * @return <code>true</code> if this dialog is resizable,
355       * <code>false</code> otherwise.
356       */
357      public boolean isResizable()
358      {
359        return resizable;
360      }
361    
362      /**
363       * Changes the resizability of this dialog box.
364       * 
365       * @param resizable <code>true</code> to make this dialog resizable,
366       * <code>false</code> to make it non-resizable.
367       */
368      public synchronized void setResizable(boolean resizable)
369      {
370        this.resizable = resizable;
371        if (peer != null)
372          {
373            DialogPeer d = (DialogPeer) peer;
374            d.setResizable(resizable);
375          }
376      }
377    
378      /**
379       * Creates this object's native peer.
380       */
381      public synchronized void addNotify()
382      {
383        if (peer == null)
384          peer = getToolkit().createDialog(this);
385        super.addNotify();
386      }
387    
388      /**
389       * Makes this dialog visible and brings it to the front. If the dialog is
390       * modal and is not already visible, this call will not return until the
391       * dialog is hidden by someone calling hide or dispose. If this is the event
392       * dispatching thread we must ensure that another event thread runs while the
393       * one which invoked this method is blocked.
394       * 
395       * @deprecated Use {@link Component#setVisible(boolean)} instead.
396       */
397      public synchronized void show()
398      {
399        super.show();
400    
401        if (isModal())
402          {
403            // If already shown (and blocked) just return
404            if (blocked)
405              return;
406    
407            /*
408             * If show is called in the dispatch thread for a modal dialog it will
409             * block so we must run another thread so the events keep being
410             * dispatched.
411             */
412            if (EventQueue.isDispatchThread())
413              {
414                EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
415                eq2 = new EventQueue();
416                eq.push(eq2);
417              }
418    
419            try
420              {
421                blocked = true;
422                wait();
423                blocked = false;
424              }
425            catch (InterruptedException e)
426              {
427                blocked = false;
428              }
429    
430            if (eq2 != null)
431              {
432                eq2.pop();
433                eq2 = null;
434              }
435          }
436      }
437    
438      /**
439       * Hides the Dialog and then causes show() to return if it is currently
440       * blocked.
441       * 
442       * @deprecated Use {@link Component#setVisible(boolean)} instead.
443       */
444      public synchronized void hide()
445      {
446        if (blocked)
447          {
448            notifyAll();
449          }
450    
451        super.hide();
452      }
453    
454      /**
455       * Disposes the Dialog and then causes show() to return if it is currently
456       * blocked.
457       */
458      public synchronized void dispose()
459      {
460        if (blocked)
461          {
462            notifyAll();
463          }
464    
465        super.dispose();
466      }
467    
468      /**
469       * Returns a debugging string for this component.
470       * 
471       * @return A debugging string for this component.
472       */
473      protected String paramString()
474      {
475        return "title+" + title + ",modal=" + modal + ",resizable=" + resizable
476                + "," + super.paramString();
477      }
478    
479      /**
480       * Returns whether this frame is undecorated or not.
481       * 
482       * @return <code>true</code> if this dialog is undecorated,
483       * <code>false</code> otherwise.
484       * 
485       * @since 1.4
486       */
487      public boolean isUndecorated()
488      {
489        return undecorated;
490      }
491    
492      /**
493       * Disables or enables decorations for this frame. This method can only be
494       * called while the frame is not displayable.
495       * 
496       * @param undecorated <code>true</code> to disable dialog decorations,
497       * <code>false</code> otherwise.
498       * 
499       * @exception IllegalComponentStateException If this frame is displayable.
500       * @since 1.4
501       */
502      public void setUndecorated(boolean undecorated)
503      {
504        if (isDisplayable())
505          throw new IllegalComponentStateException();
506    
507        this.undecorated = undecorated;
508      }
509    
510      /**
511       * Accessibility support for <code>Dialog</code>.
512       */
513      protected class AccessibleAWTDialog
514          extends AccessibleAWTWindow
515      {
516        private static final long serialVersionUID = 4837230331833941201L;
517    
518        /**
519         * Gets the role of this object.
520         * @return AccessibleRole.DIALOG 
521         */
522        public AccessibleRole getAccessibleRole()
523        {
524          return AccessibleRole.DIALOG;
525        }
526    
527        /**
528         * Gets the state set of this object.
529         * @return The current state of this dialog.
530         */
531        public AccessibleStateSet getAccessibleStateSet()
532        {
533          AccessibleStateSet states = super.getAccessibleStateSet();
534          if (isResizable())
535            states.add(AccessibleState.RESIZABLE);
536          if (isModal())
537            states.add(AccessibleState.MODAL);
538          return states;
539        }
540      }
541    
542      /**
543       * Gets the AccessibleContext associated with this <code>Dialog</code>. The
544       * context is created, if necessary.
545       * 
546       * @return the associated context
547       */
548      public AccessibleContext getAccessibleContext()
549      {
550        /* Create the context if this is the first request */
551        if (accessibleContext == null)
552          accessibleContext = new AccessibleAWTDialog();
553        return accessibleContext;
554      }
555      
556      /**
557       * Generate a unique name for this <code>Dialog</code>.
558       *
559       * @return A unique name for this <code>Dialog</code>.
560       */
561      String generateName()
562      {
563        return "dialog" + getUniqueLong();
564      }
565    
566      private static synchronized long getUniqueLong()
567      {
568        return next_dialog_number++;
569      }
570    }