001/* ----------------------------------------------------------------------------
002   The Kiwi Toolkit - A Java Class Library
003   Copyright (C) 1998-2004 Mark A. Lindner
004
005   This library is free software; you can redistribute it and/or
006   modify it under the terms of the GNU General Public License as
007   published by the Free Software Foundation; either version 2 of the
008   License, or (at your option) any later version.
009
010   This library is distributed in the hope that it will be useful,
011   but WITHOUT ANY WARRANTY; without even the implied warranty of
012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013   General Public License for more details.
014
015   You should have received a copy of the GNU General Public License
016   along with this library; if not, write to the Free Software
017   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
018   02111-1307, USA.
019 
020   The author may be contacted at: mark_a_lindner@yahoo.com
021   ----------------------------------------------------------------------------
022   $Log: KDialog.java,v $
023   Revision 1.12  2004/05/12 18:09:34  markl
024   javadoc updates
025
026   Revision 1.11  2004/05/05 23:19:38  markl
027   added setFont() method
028
029   Revision 1.10  2004/03/15 05:48:34  markl
030   moved accept/cancel logic from ComponentDialog to KDialog.
031
032   Revision 1.9  2003/01/19 09:41:00  markl
033   Javadoc & comment header updates.
034
035   Revision 1.8  2001/03/12 05:19:58  markl
036   Source code cleanup.
037
038   Revision 1.7  2000/12/18 23:37:29  markl
039   Added new constructors.
040
041   Revision 1.6  1999/07/19 04:09:52  markl
042   Fixed listener problem, renamed dispose() to destroy().
043
044   Revision 1.5  1999/07/12 08:50:21  markl
045   Listen for texture change events.
046
047   Revision 1.4  1999/07/06 09:18:24  markl
048   Added cursor method.
049
050   Revision 1.3  1999/06/03 06:47:47  markl
051   Added startFocus() method.
052
053   Revision 1.2  1999/01/10 03:22:17  markl
054   added GPL header & RCS tag
055   ----------------------------------------------------------------------------
056*/
057
058package kiwi.ui.dialog;
059
060import java.awt.*;
061import java.awt.event.*;
062import java.beans.*;
063import java.util.*;
064import javax.swing.*;
065
066import kiwi.event.*;
067import kiwi.util.*;
068import kiwi.ui.*;
069
070/** <code>KDialog</code> is a trivial extension of <code>JDialog</code>
071  * that provides support for tiling the background of the dialog with an
072  * image and for firing dismissal events.
073  * <p>
074  * <code>KDialog</code> introduces the notion of a <i>cancelled</i>
075  * dialog versus an <i>accepted</i> dialog. Collectively, these are known as
076  * <i>dialog dismissals</i>. A dialog may be <i>cancelled</i> by
077  * pressing a <i>Cancel</i> button or by closing the dialog window
078  * altogether. A dialog may be <i>accepted</i> by pressing an <i>OK</i> button
079  * or entering a value in one of the dialog's input components. It is
080  * ultimately up to the subclasser to determine what  constitutes a dialog
081  * dismissal. The convenience method <code>fireDialogDismissed()</code> is
082  * provided to generate dialog dismissal events. See
083  * <code>ComponentDialog</code> for an example of this functionality.
084  *
085  * <p><center>
086  * <img src="snapshot/KDialog.gif"><br>
087  * <i>An example KDialog.</i>
088  * </center>
089  *
090  * @see kiwi.ui.KPanel
091  * @see kiwi.ui.KFrame
092  * @see kiwi.ui.dialog.ComponentDialog
093  * @see kiwi.event.DialogDismissEvent
094  *
095  * @author Mark Lindner
096  */
097
098public class KDialog extends JDialog
099  {
100  private KPanel _main;
101  private _PropertyChangeListener propListener;
102  private Vector _listeners = new Vector();
103  private boolean cancelled = false;
104
105  /** Construct a new <code>KDialog</code>.
106    *
107    * @param parent The parent dialog for this dialog.
108    * @param title The title for this dialog.
109    * @param modal A flag specifying whether this dialog should be modal.
110    */
111  
112  public KDialog(Dialog parent, String title, boolean modal)
113    {
114    super(parent, title, modal);
115
116    _init();
117    }
118  
119  /** Construct a new <code>KDialog</code>.
120    *
121    * @param parent The parent frame for this dialog.
122    * @param title The title for this dialog.
123    * @param modal A flag specifying whether this dialog should be modal.
124    */
125
126  public KDialog(Frame parent, String title, boolean modal)
127    {
128    super(parent, title, modal);
129
130    _init();
131    }
132
133  /*
134   * Common initialization.
135   */
136  
137  private void _init()
138    {
139    getContentPane().setLayout(new GridLayout(1, 0));
140    _main = new KPanel(UIChangeManager.getDefaultTexture());
141    _main.setOpaque(true);
142    getContentPane().add(_main);
143
144    UIChangeManager.getInstance().registerComponent(getRootPane());
145    propListener = new _PropertyChangeListener();
146    UIChangeManager.getInstance().addPropertyChangeListener(propListener);
147
148    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
149
150    addWindowListener(new WindowAdapter()
151      {
152      public void windowClosing(WindowEvent evt)
153        {
154        if(canCancel())
155          doCancel();
156        else
157          doAccept();
158        }
159      });
160    }
161
162  /** Get a reference to the main container (in this case, the
163    * <code>KPanel</code> that is the child of the frame's content pane).
164    */
165
166  protected KPanel getMainContainer()
167    {
168    return(_main);
169    }
170
171  /** Set the background image for the dialog.
172   *
173   * @param image The new background image.
174    */
175
176  public void setTexture(Image image)
177    {
178    _main.setTexture(image);
179    invalidate();
180    validate();
181    repaint();
182    }
183
184  /** Add a <code>DialogDismissListener</code> to this dialog's list of
185    * listeners.
186    *
187    * @param listener The listener to add.
188    * @see #removeDialogDismissListener
189    */
190
191  public void addDialogDismissListener(DialogDismissListener listener)
192    {
193    _listeners.addElement(listener);
194    }
195
196  /** Remove a <code>DialogDismissListener</code> from this dialog's list
197    * of listeners.
198    *
199    * @param listener The listener to remove.
200    * @see #addDialogDismissListener
201    */
202
203  public void removeDialogDismissListener(DialogDismissListener listener)
204    {
205    _listeners.removeElement(listener);
206    }
207
208  /** Fire a <i>dialog dismissed</i> event. Notifies listeners that this dialog
209    * is being dismissed.
210    *
211    * @param type The event type.
212    */
213
214  protected void fireDialogDismissed(int type)
215    {
216    fireDialogDismissed(type, null);
217    }
218
219  /** Fire a <i>dialog dismissed</i> event. Notifies listeners that this dialog
220    * is being dismissed.
221    *
222    * @param type The event type.
223    * @param userObj An arbitrary user object argument to pass in the event.
224    */
225
226  protected void fireDialogDismissed(int type, Object userObj)
227    {
228    DialogDismissEvent evt = null;
229    DialogDismissListener listener;
230
231    Enumeration e = _listeners.elements();
232    while(e.hasMoreElements())
233      {
234      listener = (DialogDismissListener)e.nextElement();
235      if(evt == null) evt = new DialogDismissEvent(this, type, userObj);
236      listener.dialogDismissed(evt);
237      }
238    }
239
240  /** Show or hide the dialog.
241   *
242   * @param flag A flag specifying whether the dialog should be shown
243   * or hidden. If <code>true</code>, the <code>startFocus()</code>
244   * method is called to allow the subclasser to request focus for a
245   * given child component.
246   *
247   * @see #startFocus
248   */
249  
250  public void setVisible(boolean flag)
251    {
252    if(flag)
253      startFocus();
254
255    super.setVisible(flag);
256    }
257  
258  /** This method is called when the dialog is made visible; it should
259   * transfer focus to the appropriate child component. The default
260   * implementation does nothing.
261   */
262  
263  protected void startFocus()
264    {
265    }
266
267  /** Turn the busy cursor on or off for this dialog.
268   *
269   * @param flag If <code>true</code>, the wait cursor will be set for
270   * this dialog, otherwise the default cursor will be set.
271   */
272  
273  public void setBusyCursor(boolean flag)
274    {
275    setCursor(Cursor.getPredefinedCursor(flag ? Cursor.WAIT_CURSOR
276                                         : Cursor.DEFAULT_CURSOR));
277    }
278
279  /** Determine if this dialog can be closed.
280   *
281   * @return <code>true</code> if the dialog may be closed, and
282   * <code>false</code> otherwise. The default implementation returns
283   * <code>true</code>.
284   */
285  
286  protected boolean canClose()
287    {
288    return(true);
289    }
290  
291  /** Destroy this dialog. Call this method when the dialog is no longer
292   * needed. The dialog will detach its listeners from the
293   * <code>UIChanageManager</code>.
294   */
295
296  public void destroy()
297    {
298    UIChangeManager.getInstance().unregisterComponent(getRootPane());
299    UIChangeManager.getInstance().removePropertyChangeListener(propListener);
300    }
301
302  /** Accept user input. The dialog calls this method in response to a
303    * click on the dialog's <i>OK</i> button. If this method returns
304    * <code>true</code>, the dialog disappears; otherwise, it remains
305    * on the screen. This method can be overridden to check input in
306    * the dialog before allowing it to be dismissed. The default
307    * implementation of this method returns <code>true</code>.
308    *
309    * @return <code>true</code> if the dialog may be dismissed, and
310    * <code>false</code> otherwise.
311    *
312    * @since Kiwi 2.0
313    */
314
315  protected boolean accept()
316    {
317    return(true);
318    }
319
320  /** Programmatically accept user input.
321   *
322   * @since Kiwi 2.0
323   */
324  
325  protected void doAccept()
326    {
327    if(accept())
328      {
329      setCancelled(false);
330      fireDialogDismissed(DialogDismissEvent.OK);
331      setVisible(false);
332      dispose();
333      }
334    }
335  
336  /** Cancel the dialog. The dialog calls this method in response to a click on
337    * the dialog's <i>Cancel</i> button, or on a close of the dialog window
338    * itself. Subclassers may override this method to provide any special
339    * processing that is required when the dialog is cancelled. The default
340    * implementation of this method does nothing.
341    *
342    * @since Kiwi 2.0
343    */
344  
345  protected void cancel()
346    {
347    }
348
349  /** Programmatically cancel the dialog.
350   *
351   * @since Kiwi 2.0
352   */
353
354  protected void doCancel()
355    {
356    setCancelled(true);
357    cancel();
358    setVisible(false);
359    dispose();
360    fireDialogDismissed(DialogDismissEvent.CANCEL);
361    }
362  
363  /** Get the <i>cancelled</i> state of the dialog. This method should be
364    * called after the dialog is dismissed to determine if it was cancelled by
365    * the user.
366    *
367    * @return <code>true</code> if the dialog was cancelled, and
368    * <code>false</code> otherwise.
369    *
370    * @since Kiwi 2.0
371    */
372
373  public boolean isCancelled()
374    {
375    return(cancelled);
376    }
377
378  /** Set the <i>cancelled</i> state of the dialog. Custom dialogs which
379   * subclass <code>KDialog</code> directory may use this method to record the
380   * fact that the dialog was cancelled.
381   *
382   * @since Kiwi 2.0
383   */
384
385  protected void setCancelled(boolean flag)
386    {
387    cancelled = flag;
388    }
389
390  /** Determine if the dialog can be cancelled. This method is called in
391   * response to a click on the <i>Cancel</i> button or on the dialog
392   * window's close icon/option. Subclassers may wish to override this
393   * method to prevent cancellation of a window in certain circumstances.
394   *
395   * @return The default implementation returns<code>true</code>.
396   */
397  
398  protected boolean canCancel()
399    {
400    return(true);
401    }
402  
403  /* PropertyChangeListener */
404
405  private class _PropertyChangeListener implements PropertyChangeListener
406    {
407    public void propertyChange(PropertyChangeEvent evt)
408      {
409      if(evt.getPropertyName().equals(UIChangeManager.TEXTURE_PROPERTY))
410        setTexture((Image)evt.getNewValue());
411      }
412    }
413
414  /** Set the font for this dialog window. This method sets the font for
415   * each component in the window's component hierarchy.
416   *
417   * @param font The new font.
418   *
419   * @since Kiwi 2.0
420   */
421
422  public void setFont(Font font)
423    {
424    KiwiUtils.setFonts(getMainContainer(), font);
425    }
426 
427  }
428
429/* end of source file */