home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-06-30 | 14.8 KB | 440 lines |
- /*
- * @(#)StandardDialog.java 1.23 01/28/98
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not disclose
- * such Confidential Information and shall use it only in accordance with the
- * terms of the license agreement you entered into with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
- * OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY
- * LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR
- * ITS DERIVATIVES.
- *
- */
-
- package com.sun.java.swing;
-
- import java.awt.*;
- import java.awt.event.*;
- import java.io.*;
-
- import com.sun.java.swing.event.*;
- import com.sun.java.swing.plaf.*;
-
- /**
- A base class for a standard dialog box to request an object.
- It can be used in either
- a modal or non-modal fashion. If it has any change listeners, change
- Events will be sent to them
- when the OK or Apply buttons are pressed. If there are to be no item listeners
- then the dialog box should be created with modal==true and the start
- method will block until a new object is entered.
- <p>
- The standard pattern for doing a modal dialog box is:
- <pre>Component c = <whatever is supposed to be inside the box>
- StandardDialog d = new StandardDialog(parent, c, true);
- d.setTitle("whatever"); // if needed
- d.setDescription("paragraph to go at the top of the box"); // if needed
- d.show();
- value = c.getValue();
- </pre>
- <p>
- In normal usage, the static convenience method ask that appears
- in many standard Choosers is the easiest way to request objects:
- <p><pre>
- String c = StringChooser.ask(null, "What is your favorite color?",
- "purple", 40, null);
- </pre><p>
- @see FileChooser
- @see ColorChooser
- @see StringChooser
- @see DateChooser
- @see FontChooser
- @author James Gosling
- */
- public class StandardDialog extends Dialog {
- // Needs much more flexible UI hooks
- private Component body;
- private int style;
- private boolean locationUnknown = true;
- private PaintRef backgroundPaint;
- private GridBagConstraints cons;
- private boolean canceled = false;
- private static Font dialogFont = new Font ("Dialog", 0, 11);
- private static Component defaultParent;
- private AbstractButton[] buttonList;
- private int buttonIndex = -1;
- private Object description;
- private UI ui;
- private Icon descriptiveIcon;
- private Component cparent;
-
- public static final int PlainStyle = 0;
- public static final int QuestionStyle = 1;
- public static final int InformStyle = 2;
- public static final int WarnStyle = 3;
- public static final int ErrorStyle = 4;
-
- /** Wraps a dialog box around a Component that implents
- * the DialogBody interface. The Dialog box has OK, Cancel
- * and Apply buttons that cause ItemSelected messages to
- * be sent & the window to be closed as appropriate. */
- public StandardDialog (Component parent, Component body, boolean modal) {
- super(findFrame(parent), " ", false /* modal */ );
- cparent = parent != null ? parent : defaultParent;
- this.body = body;
- setTitle(" ");
- updateUI();
- // UIManager.addUIChangeListener(this);
- }
- private static Frame findFrame(Component c) {
- if (c == null)
- c = defaultParent;
- while (c != null && !(c instanceof Frame))
- c = c.getParent();
- if (defaultParent == null)
- defaultParent = c;
- return (Frame) c;
- }
-
- /** Before the default constructor can be used, a default parent
- has to be set up, either by a preceeding constructor invocation
- with a non-null parent, or by an explicit call to setDefaultParent.
- The dialog will be modal (there's an AWT bug that stops modal-ness
- from being changed after the dialog is created) */
- public StandardDialog () {
- this(null, null, true);
- }
-
- /** Convenience method to prompt for a button press.
- @param fparent the parent frame for the dialog box.
- fparent may be null if a default parent has
- been established with StandardDialog
- @param description a description string that will be shown
- to the user to indicate what is being requested
- @param style the style of the box (PlainStyle, QuestionStyle,
- InformStyle, WarnStyle, ErrorStyle)
- @param buttons the labels to appear on the buttons
- @param target the ChangeListener that will be informed if
- any button is hit
- @return If target is null,
- the dialog box will be modal and the method
- will return the index of the button pressed,
- or -1 if canceled.
- Otherwise, the
- dialog box is non-modal, the method returns null
- immediatly, and the listener is informed when
- appropriate. The source of the change event will
- be a StandardDialog on which you should call getButtonIndex.
- @see StandardDialog
- */
- public static int ask(Component parent, String description, int style,
- Object buttons[],
- ChangeListener target) {
- StandardDialog d = new StandardDialog (parent, null, target == null);
- d.setDescription(description);
- d.setStyle(style);
- d.setButtonList(buttons);
- if (target != null)
- d.addChangeListener(target);
- d.start();
- if (target != null)
- return -1;
- d.setVisible(false);
- d.dispose();
- return d.isCanceled() ? -1 : d.getButtonIndex();
- }
-
- /** This class keeps track of a default parent framem, which can be
- set with this method. When creating a StandardDialog, if the
- parent parameter is null, this default parent will be used. If
- the default parent is not set explicitly, it will be implicitly
- set if a StandardDialog is created with parent!=null. It'll
- make your life simpler if early on in your application (like when
- you create your main application Frame) you set the default parent. */
- public static void setDefaultParent(Component p) {
- defaultParent = p;
- }
- /** Get the parent that this dialog box was created with. A standard
- dialog's parent may be an arbitrary Component, not just a Frame.
- This Component is used to calculate the placement of the dialog box.
- In contrast, getParent() will return the Frame that contains the
- creation parent. */
- public Component getCreationParent() {
- return cparent;
- }
-
- /** Set the style for the dialog box (PlainStyle, QuestionStyle,
- InformStyle, WarnStyle, ErrorStyle) */
- public void setStyle(int style) {
- this.style = style;
- }
- public int getStyle() {
- return style;
- }
- /** Set a descriptive icon to be used in the dialog box. How it is
- used depends on the particular style. Optional. */
- public void setDescriptiveIcon(Icon icon) {
- descriptiveIcon = icon;
- }
- public Icon getDescriptiveIcon() {
- return descriptiveIcon;
- }
-
- /** A standard dialog may have a stack of descriptive information,
- usually placed at the top.
- @param d An array of descriptive information. Objects which
- are subclasses of Component will be used directly,
- Arrays of Objects will be traversed and their elements
- will be added,
- Icons will be used in new JLabels, and
- all others will be converted to strings via toString
- and used in new JLabels. Strings will be line wrapped
- with paragraph breaks at newlines. */
- public void setDescription(Object d) {
- description = d;
- }
- /** Similar to setDescription except that instead of replacing
- the whole list of descriptive information, it adds to the end. */
- public void appendDescription(Object d) {
- if (d != null)
- if (description == null)
- description = d;
- else
- description = new Object[] {
- description, d
- };
- }
- /** Similar to setDescription except that instead of replacing
- the whole list of descriptive information, it adds before the
- beginning. */
- public void prependDescription(Object d) {
- if (d != null)
- if (description == null)
- description = d;
- else
- description = new Object[] {
- d, description
- };
- }
- public Object getDescription() {
- return description;
- }
-
- /** A standard dialog may have an arbitrary list of buttons placed
- at the bottom.
- @param bl An array of buttons or button labels. Objects which
- are subclasses of AbstractButton will be used directly,
- Icons will be used directly as labels on JButtons, and
- all others will be converted to strings via toString
- and used as the labels for new JButtons. */
- public void setButtonList(Object bl[]) {
- AbstractButton[] b = new AbstractButton[bl.length];
- for (int i = 0; i < bl.length; i++)
- if (bl[i] instanceof AbstractButton)
- b[i] = (AbstractButton) bl[i];
- else if (bl[i] instanceof Icon)
- b[i] = new JButton((Icon) bl[i]);
- else
- b[i] = new JButton(bl[i].toString());
- buttonList = b;
- }
- public AbstractButton[] getButtonList() {
- return buttonList;
- }
- /** When there is an arbitrary button list, the index of the button
- that was pressed is available through getButtonIndex. */
- public int getButtonIndex() {
- return buttonIndex;
- }
- public void setButtonIndex(int bi) {
- buttonIndex = bi;
- }
-
- public void updateUI() {
- UIFactory fac = UIManager.getDefaultFactory();
- Color c = fac.getPaint("dialogforeground", "window_text").getColor();
- if (c == SystemColor.window)
- c = null;
- setForeground(c != null ? c : SystemColor.windowText);
- setBackgroundPaint(fac.getPaint("dialogbackground", "window"));
- setFont(fac.getFont("dialogfont", "Dialog-11"));
- // Can't use UIFactory.getUI since it demands ComponentUIs
- String className = fac.getProperty("StandardDialogUI",
- "com.sun.java.swing.basic.BasicStandardDialogUI");
- try {
- Class uiClass = Class.forName(className);
- Class createUIArgClass = this.getClass();
- java.lang.reflect.Method m = null;
- do {
- try {
- m = uiClass.getMethod("createUI",
- /**INDENT** Error@277: Unbalanced parens */
- new Class[] {
- createUIArgClass
- /**INDENT** Warning@279: Extra ) */
- });
- } catch(NoSuchMethodException nsme) {
- // The target class doesn't define createUI(), try its
- // parent.
- createUIArgClass = createUIArgClass.getSuperclass();
- if (createUIArgClass == null) {
- System.err.println("createUI() not found in " +
- className);
- return;
- }
- }
- } while (m == null);
- /**INDENT** Error@291: Unbalanced parens */
- ui = (UI) (m.invoke(null, new Object[] {
- this
- /**INDENT** Warning@293: Extra ) */
- /**INDENT** Warning@293: Extra ) */
- }));
- } catch(Throwable cnf) {
- cnf.printStackTrace();
- return;
- }
- }
- public void dispose() {
- // UIManager.removeUIChangeListener(this);
- // ui.uninstallUI(this);
- super.dispose();
- }
-
- private ChangeEvent changeEvent;
- private EventListenerList listenerList = new EventListenerList();
- public boolean hasChangeListener() {
- Object [] o = listenerList.getListenerList();
- if (o != null)
- for (int i = o.length; (i -= 2) >= 0;)
- if (o[i] == ChangeListener.class)
- return true;
- return false;
- }
-
- /**
- * Adds a ChangeListener to the button.
- */
- public void addChangeListener(ChangeListener l) {
- listenerList.add(ChangeListener.class, l);
- }
-
- /**
- * Removes a ChangeListener from the button.
- */
- public void removeChangeListener(ChangeListener l) {
- listenerList.remove(ChangeListener.class, l);
- }
- protected void fireStateChanged() {
- // Guaranteed to return a non-null array
- Object [] listeners = listenerList.getListenerList();
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ChangeListener.class) {
- // Lazily create the event:
- if (changeEvent == null)
- changeEvent = new ChangeEvent(body == null ?
- this :
- ((Component) (body)));
- ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent);
- }
- }
- }
-
- public synchronized void notifyChange() {
- fireStateChanged();
- notifyAll();
- }
-
- /** Once the Dialog box is set up, start() pops the dialog box up
- and begins the interaction. If the dialog box is modal, start()
- doesn't return until the interaction is complete. Otherwise it
- returns immediatly and the ChangeListeners will be notified when
- a color is selected. */
- public synchronized void start() {
- ui.start(this);
- if (hasChangeListener())
- return;
- try {
- // can't use instanceof EventDispatchThread because the class isn't public
- if (Thread.currentThread().getClass().getName().endsWith("EventDispatchThread")) {
- EventQueue theQueue = getToolkit().getSystemEventQueue();
- while (isVisible()) {
- // This is essentially the body of EventDispatchThread
- AWTEvent event = theQueue.getNextEvent();
- Object src = event.getSource();
- // can't call theQueue.dispatchEvent, so I pasted it's body here
- /*if (event instanceof ActiveEvent) {
- ((ActiveEvent) event).dispatch();
- } else */ if (src instanceof Component) {
- ((Component) src).dispatchEvent(event);
- } else if (src instanceof MenuComponent) {
- ((MenuComponent) src).dispatchEvent(event);
- } else {
- System.err.println("unable to dispatch event: " + event);
- }
- }
- } else
- while (isVisible())
- wait();
- } catch(InterruptedException e){}
- }
- /** true iff this dialog has been canceled by the user */
- public boolean isCanceled() {
- return canceled;
- }
- public void setCanceled(boolean b) {
- canceled = b;
- }
- public Component getBody() {
- return body;
- }
- public void setBackgroundPaint(PaintRef bkg) {
- if (backgroundPaint != bkg) {
- Color c = bkg.getColor();
- setBackground(c != null ? c : SystemColor.window);
- backgroundPaint = bkg;
- repaint();
- }
- }
- public PaintRef getBackgroundPaint() {
- return backgroundPaint;
- }
-
- public void paint(Graphics g) {
- if (backgroundPaint != null && backgroundPaint.getTile() != null)
- backgroundPaint.fill(g, this);
- super.paint(g);
- }
- public void update(Graphics g) {
- if (backgroundPaint != null)
- backgroundPaint.fill(g, this);
- super.paint(g);
- }
-
- /** If the component that is the body of a StandardDialog implements to
- OKcheck interface, then the isOK() method will be called after the
- user has pressed the OK button to determine if it really is OK. */
- public static interface OKcheck {
- boolean isOK();
- }
-
- /** If you want to implement a new user interface for standard dialogs,
- this is the interface you have to implement. */
- public static interface UI {
- /** Once the Dialog box is set up, start() pops the dialog box up
- and begins the interaction. If the dialog box is modal, start()
- doesn't return until the interaction is complete. Otherwise it
- returns immediatly and the ChangeListeners will be notified when
- a color is selected. */
- public void start(StandardDialog dlg);
- }
- }
-