KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > DialogDisplayer


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide;
20
21 import org.openide.util.Lookup;
22 import org.openide.util.Utilities;
23
24 import java.awt.*;
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.awt.event.ActionListener JavaDoc;
27 import java.awt.event.KeyEvent JavaDoc;
28 import java.awt.event.WindowAdapter JavaDoc;
29 import java.awt.event.WindowEvent JavaDoc;
30
31 import java.beans.PropertyChangeEvent JavaDoc;
32 import java.beans.PropertyChangeListener JavaDoc;
33
34 import java.util.Arrays JavaDoc;
35 import java.util.HashSet JavaDoc;
36 import java.util.Set JavaDoc;
37
38 import javax.swing.*;
39
40
41 /** Permits dialogs to be displayed.
42  * @author Jesse Glick
43  * @since 3.14
44  */

45 public abstract class DialogDisplayer {
46     /** Subclass constructor. */
47     protected DialogDisplayer() {
48     }
49
50     /** Get the default dialog displayer.
51      * @return the default instance from lookup
52      */

53     public static DialogDisplayer getDefault() {
54         DialogDisplayer dd = (DialogDisplayer) Lookup.getDefault().lookup(DialogDisplayer.class);
55
56         if (dd == null) {
57             dd = new Trivial();
58         }
59
60         return dd;
61     }
62
63     /** Notify the user of something in a message box, possibly with feedback.
64      * <p>To support both GUI and non-GUI use, this method may be called
65      * from any thread (providing you are not holding any locks), and
66      * will block the caller's thread. In GUI mode, it will be run in the AWT
67      * event thread automatically. If you wish to hold locks, or do not
68      * need the result object immediately or at all, please make this call
69      * asynchronously (e.g. from the request processor).
70      * @param descriptor description of the notification
71      * @return the option that caused the message box to be closed
72      */

73     public abstract Object JavaDoc notify(NotifyDescriptor descriptor);
74
75     /** Notify the user of something in a message box, possibly with feedback,
76      * this method method may be called
77      * from any thread. The thread will return immediately and
78      * the dialog will be shown <q>later</q>, usually when AWT thread
79      * is empty and can handle the request.
80      *
81      * <p class="non-normative">
82      * Implementation note: Since version 7.3, implementation improved to work
83      * also before main window is opened. For example: When method is called
84      * from ModuleInstall.restored, then modal dialog is opened and blocks main
85      * window until dialog is closed. Typical use case is login dialog.
86      * </p>
87      *
88      * @param descriptor description of the notification
89      * @since 7.0
90      */

91     public void notifyLater(final NotifyDescriptor descriptor) {
92         SwingUtilities.invokeLater(new Runnable JavaDoc() {
93             public void run() {
94                 DialogDisplayer.this.notify(descriptor);
95             }
96         });
97     }
98
99     /** Get a new standard dialog.
100      * The dialog is designed and created as specified in the parameter.
101      * Anyone who wants a dialog with standard buttons and
102      * standard behavior should use this method.
103      * <p><strong>Do not cache</strong> the resulting dialog if it
104      * is modal and try to reuse it! Always create a new dialog
105      * using this method if you need to show a dialog again.
106      * Otherwise previously closed windows can reappear.
107      * @param descriptor general description of the dialog
108      * @return the new dialog
109      */

110     public abstract Dialog createDialog(DialogDescriptor descriptor);
111
112     /**
113      * Minimal implementation suited for standalone usage.
114      * @see "#30031"
115      */

116     private static final class Trivial extends DialogDisplayer {
117         public Object JavaDoc notify(NotifyDescriptor nd) {
118             JDialog dialog = new StandardDialog(nd.getTitle(), true, nd, null, null);
119             dialog.setVisible(true);
120
121             return (nd.getValue() != null) ? nd.getValue() : NotifyDescriptor.CLOSED_OPTION;
122         }
123
124         public Dialog createDialog(final DialogDescriptor dd) {
125             final StandardDialog dialog = new StandardDialog(
126                     dd.getTitle(), dd.isModal(), dd, dd.getClosingOptions(), dd.getButtonListener()
127                 );
128             dd.addPropertyChangeListener(new DialogUpdater(dialog, dd));
129
130             return dialog;
131         }
132
133         /**
134          * Given a message object, create a displayable component from it.
135          */

136         private static Component message2Component(Object JavaDoc message) {
137             if (message instanceof Component) {
138                 return (Component) message;
139             } else if (message instanceof Object JavaDoc[]) {
140                 Object JavaDoc[] sub = (Object JavaDoc[]) message;
141                 JPanel panel = new JPanel();
142                 panel.setLayout(new FlowLayout());
143
144                 for (int i = 0; i < sub.length; i++) {
145                     panel.add(message2Component(sub[i]));
146                 }
147
148                 return panel;
149             } else if (message instanceof Icon) {
150                 return new JLabel((Icon) message);
151             } else {
152                 // bugfix #35742, used JTextArea to correctly word-wrapping
153
String JavaDoc text = message.toString();
154                 JTextArea area = new JTextArea(text);
155                 Color c = UIManager.getColor("Label.background"); // NOI18N
156

157                 if (c != null) {
158                     area.setBackground(c);
159                 }
160
161                 area.setLineWrap(true);
162                 area.setWrapStyleWord(true);
163                 area.setEditable(false);
164                 area.setTabSize(4); // looks better for module sys messages than 8
165

166                 area.setColumns(40);
167
168                 if (text.indexOf('\n') != -1) {
169                     // Complex multiline message.
170
return new JScrollPane(area);
171                 } else {
172                     // Simple message.
173
return area;
174                 }
175             }
176         }
177
178         private static Component option2Button(Object JavaDoc option, NotifyDescriptor nd, ActionListener JavaDoc l, JRootPane rp) {
179             if (option instanceof AbstractButton) {
180                 AbstractButton b = (AbstractButton) option;
181                 b.addActionListener(l);
182
183                 return b;
184             } else if (option instanceof Component) {
185                 return (Component) option;
186             } else if (option instanceof Icon) {
187                 return new JLabel((Icon) option);
188             } else {
189                 String JavaDoc text;
190                 boolean defcap;
191
192                 if (option == NotifyDescriptor.OK_OPTION) {
193                     text = "OK"; // XXX I18N
194
defcap = true;
195                 } else if (option == NotifyDescriptor.CANCEL_OPTION) {
196                     text = "Cancel"; // XXX I18N
197
defcap = false;
198                 } else if (option == NotifyDescriptor.YES_OPTION) {
199                     text = "Yes"; // XXX I18N
200
defcap = true;
201                 } else if (option == NotifyDescriptor.NO_OPTION) {
202                     text = "No"; // XXX I18N
203
defcap = false;
204                 } else if (option == NotifyDescriptor.CLOSED_OPTION) {
205                     throw new IllegalArgumentException JavaDoc();
206                 } else {
207                     text = option.toString();
208                     defcap = false;
209                 }
210
211                 JButton b = new JButton(text);
212
213                 if (defcap && (rp.getDefaultButton() == null)) {
214                     rp.setDefaultButton(b);
215                 }
216
217                 // added a simple accessible name to buttons
218
b.getAccessibleContext().setAccessibleName(text);
219                 b.addActionListener(l);
220
221                 return b;
222             }
223         }
224
225         private static final class StandardDialog extends JDialog {
226             final NotifyDescriptor nd;
227             private Component messageComponent;
228             private final JPanel buttonPanel;
229             private final Object JavaDoc[] closingOptions;
230             private final ActionListener JavaDoc buttonListener;
231             private boolean haveFinalValue = false;
232
233             public StandardDialog(
234                 String JavaDoc title, boolean modal, NotifyDescriptor nd, Object JavaDoc[] closingOptions, ActionListener JavaDoc buttonListener
235             ) {
236                 super((Frame) null, title, modal);
237                 this.nd = nd;
238                 this.closingOptions = closingOptions;
239                 this.buttonListener = buttonListener;
240                 getContentPane().setLayout(new BorderLayout());
241                 setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
242                 updateMessage();
243                 buttonPanel = new JPanel();
244                 buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
245                 updateOptions();
246                 getContentPane().add(buttonPanel, BorderLayout.SOUTH, 1);
247
248                 KeyStroke k = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
249                 Object JavaDoc actionKey = "cancel"; // NOI18N
250
getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(k, actionKey);
251
252                 Action cancelAction = new AbstractAction() {
253                         public void actionPerformed(ActionEvent JavaDoc ev) {
254                             cancel();
255                         }
256                     };
257
258                 getRootPane().getActionMap().put(actionKey, cancelAction);
259                 addWindowListener(
260                     new WindowAdapter JavaDoc() {
261                         public void windowClosing(WindowEvent JavaDoc ev) {
262                             if (!haveFinalValue) {
263                                 StandardDialog.this.nd.setValue(NotifyDescriptor.CLOSED_OPTION);
264                             }
265                         }
266                     }
267                 );
268                 pack();
269
270                 Rectangle r = Utilities.getUsableScreenBounds();
271                 int maxW = (r.width * 9) / 10;
272                 int maxH = (r.height * 9) / 10;
273                 Dimension d = getPreferredSize();
274                 d.width = Math.min(d.width, maxW);
275                 d.height = Math.min(d.height, maxH);
276                 setBounds(Utilities.findCenterBounds(d));
277             }
278
279             private void cancel() {
280                 nd.setValue(NotifyDescriptor.CANCEL_OPTION);
281                 haveFinalValue = true;
282                 dispose();
283             }
284
285             public void updateMessage() {
286                 if (messageComponent != null) {
287                     getContentPane().remove(messageComponent);
288                 }
289
290                 //System.err.println("updateMessage: " + nd.getMessage());
291
messageComponent = message2Component(nd.getMessage());
292                 getContentPane().add(messageComponent, BorderLayout.CENTER);
293             }
294
295             public void updateOptions() {
296                 Set JavaDoc<Object JavaDoc> addedOptions = new HashSet JavaDoc<Object JavaDoc>(5);
297                 Object JavaDoc[] options = nd.getOptions();
298
299                 if (options == null) {
300                     switch (nd.getOptionType()) {
301                     case NotifyDescriptor.DEFAULT_OPTION:
302                     case NotifyDescriptor.OK_CANCEL_OPTION:
303                         options = new Object JavaDoc[] { NotifyDescriptor.OK_OPTION, NotifyDescriptor.CANCEL_OPTION, };
304
305                         break;
306
307                     case NotifyDescriptor.YES_NO_OPTION:
308                         options = new Object JavaDoc[] { NotifyDescriptor.YES_OPTION, NotifyDescriptor.NO_OPTION, };
309
310                         break;
311
312                     case NotifyDescriptor.YES_NO_CANCEL_OPTION:
313                         options = new Object JavaDoc[] {
314                                 NotifyDescriptor.YES_OPTION, NotifyDescriptor.NO_OPTION, NotifyDescriptor.CANCEL_OPTION,
315                             };
316
317                         break;
318
319                     default:
320                         throw new IllegalArgumentException JavaDoc();
321                     }
322                 }
323
324                 //System.err.println("prep: " + Arrays.asList(options) + " " + Arrays.asList(closingOptions) + " " + buttonListener);
325
buttonPanel.removeAll();
326
327                 JRootPane rp = getRootPane();
328
329                 for (int i = 0; i < options.length; i++) {
330                     addedOptions.add(options[i]);
331                     buttonPanel.add(option2Button(options[i], nd, makeListener(options[i]), rp));
332                 }
333
334                 options = nd.getAdditionalOptions();
335
336                 if (options != null) {
337                     for (int i = 0; i < options.length; i++) {
338                         addedOptions.add(options[i]);
339                         buttonPanel.add(option2Button(options[i], nd, makeListener(options[i]), rp));
340                     }
341                 }
342
343                 if (closingOptions != null) {
344                     for (int i = 0; i < closingOptions.length; i++) {
345                         if (addedOptions.add(closingOptions[i])) {
346                             ActionListener JavaDoc l = makeListener(closingOptions[i]);
347                             attachActionListener(closingOptions[i], l);
348                         }
349                     }
350                 }
351             }
352
353             private void attachActionListener(Object JavaDoc comp, ActionListener JavaDoc l) {
354                 // on JButtons attach simply by method call
355
if (comp instanceof JButton) {
356                     JButton b = (JButton) comp;
357                     b.addActionListener(l);
358
359                     return;
360                 } else {
361                     // we will have to use dynamic method invocation to add the action listener
362
// to generic component (and we succeed only if it has the addActionListener method)
363
java.lang.reflect.Method JavaDoc m;
364
365                     try {
366                         m = comp.getClass().getMethod("addActionListener", new Class JavaDoc[] { ActionListener JavaDoc.class }); // NOI18N
367

368                         try {
369                             m.setAccessible(true);
370                         } catch (SecurityException JavaDoc se) {
371                             m = null; // no jo, we cannot make accessible
372
}
373                     } catch (NoSuchMethodException JavaDoc e) {
374                         m = null; // no jo, we cannot attach ActionListener to this Component
375
} catch (SecurityException JavaDoc e2) {
376                         m = null; // no jo, we cannot attach ActionListener to this Component
377
}
378
379                     if (m != null) {
380                         try {
381                             m.invoke(comp, new Object JavaDoc[] { l });
382                         } catch (Exception JavaDoc e) {
383                             // not succeeded, so give up
384
}
385                     }
386                 }
387             }
388
389             private ActionListener JavaDoc makeListener(final Object JavaDoc option) {
390                 return new ActionListener JavaDoc() {
391                         public void actionPerformed(ActionEvent JavaDoc e) {
392                             //System.err.println("actionPerformed: " + option);
393
nd.setValue(option);
394
395                             if (buttonListener != null) {
396                                 // #34485: some listeners expect that the action source is the option, not the button
397
ActionEvent JavaDoc e2 = new ActionEvent JavaDoc(
398                                         option, e.getID(), e.getActionCommand(), e.getWhen(), e.getModifiers()
399                                     );
400                                 buttonListener.actionPerformed(e2);
401                             }
402
403                             if ((closingOptions == null) || Arrays.asList(closingOptions).contains(option)) {
404                                 haveFinalValue = true;
405                                 setVisible(false);
406                             }
407                         }
408                     };
409             }
410         }
411
412         private static class DialogUpdater implements PropertyChangeListener JavaDoc {
413
414             private StandardDialog dialog;
415
416             private DialogDescriptor dd;
417
418             public DialogUpdater(StandardDialog dialog, DialogDescriptor dd) {
419                 super();
420                 this.dialog = dialog;
421                 this.dd = dd;
422             }
423
424             public void propertyChange(PropertyChangeEvent JavaDoc ev) {
425                 String JavaDoc pname = ev.getPropertyName();
426                 if (NotifyDescriptor.PROP_TITLE.equals(pname)) {
427                     dialog.setTitle(dd.getTitle());
428                 } else
429                     if (NotifyDescriptor.PROP_MESSAGE.equals(pname)) {
430                         dialog.updateMessage();
431                         dialog.validate();
432                         dialog.repaint();
433                     } else
434                         if (NotifyDescriptor.PROP_OPTIONS.equals(pname) || NotifyDescriptor.PROP_OPTION_TYPE.equals(pname)) {
435                             dialog.updateOptions();
436                             dialog.validate();
437                             dialog.repaint();
438                         } else {
439                         }
440             }
441         }
442
443     }
444 }
445
Popular Tags