Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: edu/emory/mathcs/util/swing/JDetailedMessageBox.java


1   /* ***** BEGIN LICENSE BLOCK *****
2    * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3    *
4    * The contents of this file are subject to the Mozilla Public License Version
5    * 1.1 (the "License"); you may not use this file except in compliance with
6    * the License. You may obtain a copy of the License at
7    * http://www.mozilla.org/MPL/
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis,
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11   * for the specific language governing rights and limitations under the
12   * License.
13   *
14   * The Original Code is the Emory Utilities.
15   *
16   * The Initial Developer of the Original Code is
17   * The Distributed Computing Laboratory, Emory University.
18   * Portions created by the Initial Developer are Copyright (C) 2002
19   * the Initial Developer. All Rights Reserved.
20   *
21   * Alternatively, the contents of this file may be used under the terms of
22   * either the GNU General Public License Version 2 or later (the "GPL"), or
23   * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
24   * in which case the provisions of the GPL or the LGPL are applicable instead
25   * of those above. If you wish to allow use of your version of this file only
26   * under the terms of either the GPL or the LGPL, and not to allow others to
27   * use your version of this file under the terms of the MPL, indicate your
28   * decision by deleting the provisions above and replace them with the notice
29   * and other provisions required by the GPL or the LGPL. If you do not delete
30   * the provisions above, a recipient may use your version of this file under
31   * the terms of any one of the MPL, the GPL or the LGPL.
32   *
33   * ***** END LICENSE BLOCK ***** */
34  
35  package edu.emory.mathcs.util.swing;
36  
37  import java.util.*;
38  
39  import java.awt.*;
40  import java.awt.event.*;
41  import javax.swing.*;
42  
43  /**
44   * Message box with the expandable detail pane at the bottom of the window.
45   * Allows users to show/hide message details that may be represented
46   * by any Swing component.
47   * Construction and usage patterns are similar to that of {@link JOptionPane}
48   * except that the "details" object is additionally required. If this
49   * object is a JComponent, it is used as is;
50   * otherwise, it is converted to string and displayed in a text box.
51   *
52   * @see JOptionPane for detailed documentation
53   *
54   * @author Dawid Kurzyniec
55   * @version 1.0
56   */
57  
58  public class JDetailedMessageBox extends JDialog {
59  
60      static Color BACKGROUND_COLOR = UIManager.getColor("OptionPane.background");
61      static Font MESSAGE_FONT = UIManager.getFont("OptionPane.messageFont");
62      static Font BUTTON_FONT = UIManager.getFont("OptionPane.font");
63      static Font LABEL_FONT = UIManager.getFont("Label.font");
64  
65      JPanel detailPane;
66      JButton detailBtn;
67      JButton initialFocus;
68      int selectedBtn = -1;
69      int defaultBtn;
70      DetailButtonListener dblistener = new DetailButtonListener();
71  
72      JDetailedMessageBox(Dialog owner, String title) {
73          super(owner, title, true);
74      }
75  
76      JDetailedMessageBox(Frame owner, String title) {
77          super(owner, title, true);
78      }
79  
80      public static JDetailedMessageBox newInstance(
81          Component parentComponent, String title,
82          Object message, int messageType, int optionType,
83          Object details)
84      {
85          return newInstance(parentComponent, title, message, messageType,
86                             optionType, iconForMessageType(messageType), details);
87      }
88  
89      public static JDetailedMessageBox newInstance(
90          Component parentComponent, String title,
91          Object message, int messageType, int optionType,
92          Icon icon, Object details)
93      {
94          return newInstance(parentComponent, title, message, messageType,
95                             optionType, icon, null, details);
96      }
97  
98      public static JDetailedMessageBox newInstance(
99          Component parentComponent, String title,
100         Object message, int messageType, int optionType,
101         Icon icon, Object[] options, Object details)
102     {
103         return newInstance(parentComponent, title, message, messageType,
104                            optionType, icon, options, 0, details);
105     }
106 
107     public static JDetailedMessageBox newInstance(
108         Component parentComponent, String title,
109         Object message, int messageType, int optionType,
110         Icon icon, Object[] options, int initialIndex, Object details)
111     {
112         return newInstance(parentComponent, title, message, messageType,
113                            optionType, (Object)icon, options, initialIndex,
114                            details);
115     }
116 
117     public static JDetailedMessageBox newInstance(
118         Component parentComponent, String title,
119         Object message, int messageType, int optionType,
120         Object icon, Object[] options, int initialIndex, Object details)
121     {
122         final JDetailedMessageBox dialog;
123 
124         Window window = getWindowForComponent(parentComponent);
125         if (window instanceof Frame) {
126             dialog = new JDetailedMessageBox((Frame)window, title);
127         } else {
128             dialog = new JDetailedMessageBox((Dialog)window, title);
129         }
130 
131         Container contentPane = dialog.getContentPane();
132         contentPane.setLayout(new GridBagLayout());
133         //JPanel iconPane = new JPanel();
134 
135         Component iconComponent;
136         if (icon == null) {
137             iconComponent = null;
138         }
139         else if (icon instanceof Component) {
140             iconComponent = (Component)icon;
141         }
142         else {
143             JLabel iconLabel;
144             if (icon instanceof Icon) {
145                 iconLabel = new JLabel((Icon)icon);
146             } else {
147                 iconLabel = new JLabel(icon.toString());
148             }
149             iconLabel.setBackground(BACKGROUND_COLOR);
150             iconComponent = iconLabel;
151         }
152 
153         if (iconComponent != null) {
154             contentPane.add(iconComponent, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0
155                 ,GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(6, 6, 5, 5), 0, 0));
156         }
157 
158         //JPanel auxMsgPane = new JPanel();
159         JPanel msgPane = new JPanel();
160         contentPane.add(msgPane, new GridBagConstraints(1, 0, 1, 1, 1.0, 0.001
161             ,GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(6, 6, 5, 5), 0, 0));
162         //auxMsgPane.setLayout(new BorderLayout());
163         //auxMsgPane.add(msgPane, BorderLayout.NORTH);
164         JPanel auxBtnPane = new JPanel();
165         JPanel btnPane = new JPanel();
166         contentPane.add(auxBtnPane, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0
167             ,GridBagConstraints.NORTHEAST, GridBagConstraints.VERTICAL, new Insets(6, 6, 5, 5), 0, 0));
168         auxBtnPane.setLayout(new BorderLayout());
169         auxBtnPane.add(btnPane, BorderLayout.NORTH);
170 
171         // buttons
172 
173         btnPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
174         GridLayout btnLayout = new GridLayout(0, 1, 5, 5);
175         btnPane.setLayout(btnLayout);
176         if (options == null) {
177             options = buttonsFromOptionType(optionType, dialog.getLocale());
178         }
179         for (int i = 0; i < options.length; i++) {
180             Object btnObj = options[i];
181             JButton jbutton;
182             if (btnObj instanceof JButton) {
183                 jbutton = (JButton)btnObj;
184             } else {
185                 jbutton = new JButton(btnObj.toString());
186             }
187             if (i == initialIndex) {
188                 dialog.getRootPane().setDefaultButton(jbutton);
189                 dialog.initialFocus = jbutton;
190             }
191             configureButton(jbutton);
192             jbutton.addActionListener(dialog.new ButtonActionListener(i));
193             btnPane.add(jbutton);
194         }
195 
196         // message
197 
198         msgPane.setLayout(new BorderLayout());
199         if (message instanceof Component) {
200             msgPane.add((Component)message);
201         } else {
202             String msg = message.toString();
203             JTextArea ta = new JTextArea(msg);
204             Font font = getMessageFont(dialog);
205             if (font != null) ta.setFont(font);
206             ta.setEditable(false);
207             ta.setBackground(BACKGROUND_COLOR);
208             // check preferred witdh before word wrapping
209             // try to determine best dimensions for message pane, considering
210             // number of buttons and the amount of text to display
211             Dimension tapref = ta.getPreferredSize();
212             int width = (int)tapref.getWidth();
213             int height = (int)tapref.getHeight();
214             int preflines = (int)(btnPane.getPreferredSize().getHeight()/height);
215             if (preflines == 0) preflines = 1;
216             if (width > 250) {
217                 width = width / preflines;
218                 if (width < 250) {
219                     width = 250;
220                 }
221                 else if (width > 500) {
222                     width = 500;
223                 }
224             }
225 
226             // hint for the view to correctly compute preferred height
227             // (otherwise, height does not reflect wrapped lines)
228             ta.setSize(width, Integer.MAX_VALUE);
229             ta.setLineWrap(true);
230             ta.setWrapStyleWord(true);
231             msgPane.add(ta, BorderLayout.CENTER);
232             ta.invalidate();
233         }
234 
235 
236         // "details" button
237 
238         JButton dbtn = new JButton();
239         configureButton(dbtn);
240         auxBtnPane.add(dbtn, BorderLayout.SOUTH);
241         dialog.detailBtn = dbtn;
242         dbtn.addActionListener(dialog.dblistener);
243 
244         // detail pane
245 
246         JPanel detailPane = new JPanel();
247 
248         //detailPane.setPreferredSize(new Dimension(0, 150));
249         detailPane.setLayout(new BorderLayout());
250         if (details instanceof Component) {
251             detailPane.add((Component)details, BorderLayout.CENTER);
252         } else {
253             JScrollPane scrollPane = new JScrollPane();
254             detailPane.add(scrollPane, BorderLayout.CENTER);
255             JTextArea dtt = new JTextArea(details.toString());
256             dtt.setEditable(false);
257             dtt.setTabSize(4);
258             scrollPane.setViewport(new DetailViewport());
259             scrollPane.setViewportView(dtt);
260         }
261 
262         Dimension dsize = detailPane.getSize();
263         dsize.height = 150;
264         detailPane.setSize(dsize);
265         detailPane.invalidate();
266 
267         dialog.detailPane = detailPane;
268         contentPane.add(detailPane, new GridBagConstraints(0, 1, 3, 1, 1.0, 1.0
269             ,GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(6, 6, 5, 5), 0, 0));
270         dialog.dblistener.update(false);
271 
272         if (JDialog.isDefaultLookAndFeelDecorated()) {
273             int style = styleFromMessageType(messageType);
274             boolean supportsWindowDecorations =
275             UIManager.getLookAndFeel().getSupportsWindowDecorations();
276             if (supportsWindowDecorations) {
277                 dialog.setUndecorated(true);
278                 dialog.getRootPane().setWindowDecorationStyle(style);
279             }
280         }
281 
282         //dialog.setResizable(false);
283         dialog.pack();
284 
285         dialog.setLocationRelativeTo(parentComponent);
286         dialog.addWindowListener(new WindowAdapter() {
287             private boolean gotFocus = false;
288             public void windowClosing(WindowEvent we) {
289                 dialog.selectedBtn = -1;
290             }
291             public void windowGainedFocus(WindowEvent we) {
292                 // Once window gets focus, set initial focus
293                 if (!gotFocus) {
294                     dialog.selectedBtn = dialog.defaultBtn;
295                     gotFocus = true;
296                 }
297             }
298         });
299         dialog.addComponentListener(new ComponentAdapter() {
300             public void componentShown(ComponentEvent ce) {
301                 // reset value to ensure closing works properly
302                 dialog.selectedBtn = -1;
303             }
304         });
305         return dialog;
306     }
307 
308     static Window getWindowForComponent(Component parentComponent)
309         throws HeadlessException {
310         if (parentComponent == null)
311             return JOptionPane.getRootFrame();
312         if (parentComponent instanceof Frame || parentComponent instanceof Dialog)
313             return (Window)parentComponent;
314         return JDetailedMessageBox.getWindowForComponent(parentComponent.getParent());
315     }
316 
317     public void setInitialFocus() {
318         if (initialFocus != null) {
319             initialFocus.requestFocus();
320         }
321     }
322 
323     public int getValue() {
324         return selectedBtn;
325     }
326 
327     private static int styleFromMessageType(int messageType) {
328         switch (messageType) {
329         case JOptionPane.ERROR_MESSAGE:
330             return JRootPane.ERROR_DIALOG;
331         case JOptionPane.QUESTION_MESSAGE:
332             return JRootPane.QUESTION_DIALOG;
333         case JOptionPane.WARNING_MESSAGE:
334             return JRootPane.WARNING_DIALOG;
335         case JOptionPane.INFORMATION_MESSAGE:
336             return JRootPane.INFORMATION_DIALOG;
337         case JOptionPane.PLAIN_MESSAGE:
338         default:
339             return JRootPane.PLAIN_DIALOG;
340         }
341     }
342 
343     private static JButton[] buttonsFromOptionType(int optionType, Locale l) {
344         JButton[] options;
345         if (optionType == JOptionPane.YES_NO_OPTION) {
346             options = new JButton[2];
347             options[0] = new JButton(UIManager.get("OptionPane.yesButtonText",l).toString());
348             options[0].setMnemonic(getMnemonic("OptionPane.yesButtonMnemonic",l));
349             options[1] = new JButton(UIManager.get("OptionPane.noButtonText",l).toString());
350             options[1].setMnemonic(getMnemonic("OptionPane.noButtonMnemonic", l));
351         }
352         else if (optionType == JOptionPane.YES_NO_CANCEL_OPTION) {
353             options = new JButton[3];
354             options[0] = new JButton(UIManager.get("OptionPane.yesButtonText",l).toString());
355             options[0].setMnemonic(getMnemonic("OptionPane.yesButtonMnemonic",l));
356             options[1] = new JButton(UIManager.get("OptionPane.noButtonText",l).toString());
357             options[1].setMnemonic(getMnemonic("OptionPane.noButtonMnemonic", l));
358             options[2] = new JButton(UIManager.get("OptionPane.cancelButtonText",l).toString());
359             options[2].setMnemonic(getMnemonic("OptionPane.cancelButtonMnemonic", l));
360         }
361         else if (optionType == JOptionPane.OK_CANCEL_OPTION) {
362             options = new JButton[2];
363             options[0] = new JButton(UIManager.get("OptionPane.okButtonText",l).toString());
364             options[0].setMnemonic(getMnemonic("OptionPane.okButtonMnemonic",l));
365             options[1] = new JButton(UIManager.get("OptionPane.cancelButtonText",l).toString());
366             options[1].setMnemonic(getMnemonic("OptionPane.cancelButtonMnemonic", l));
367         }
368         else {
369             options = new JButton[1];
370             options[0] = new JButton(UIManager.get("OptionPane.okButtonText",l).toString());
371             options[0].setMnemonic(getMnemonic("OptionPane.okButtonMnemonic",l));
372         }
373         return options;
374     }
375 
376     private static Icon iconForMessageType(int messageType) {
377         if(messageType < 0 || messageType > 3)
378             return null;
379         switch(messageType) {
380         case 0:
381             return UIManager.getIcon("OptionPane.errorIcon");
382         case 1:
383             return UIManager.getIcon("OptionPane.informationIcon");
384         case 2:
385             return UIManager.getIcon("OptionPane.warningIcon");
386         case 3:
387             return UIManager.getIcon("OptionPane.questionIcon");
388         }
389         return null;
390     }
391 
392     private static int getMnemonic(String key, Locale l) {
393         String value = (String)UIManager.get(key, l);
394 
395         if (value == null) {
396             return 0;
397         }
398         try {
399             return Integer.parseInt(value);
400         }
401         catch (NumberFormatException nfe) { }
402         return 0;
403     }
404 
405     private class DetailButtonListener implements ActionListener {
406         boolean shown = false;
407 
408         public void actionPerformed(ActionEvent evt) {
409             update(!shown);
410         }
411 
412         void update(boolean show) {
413             String label = show ? ">> Details" : "Details >>";
414             detailBtn.setText(label);
415             detailPane.setVisible(show);
416             if (show == shown) return;
417             this.shown = show;
418             pack();
419         }
420     }
421 
422     protected class ButtonActionListener implements ActionListener {
423         int buttonIndex;
424         public ButtonActionListener(int buttonIndex) {
425             this.buttonIndex = buttonIndex;
426         }
427         public void actionPerformed(ActionEvent e) {
428             selectedBtn = buttonIndex;
429             setVisible(false);
430         }
431     }
432 
433     private static void configureButton(JButton btn) {
434         if (BUTTON_FONT != null && btn.getFont() == null) {
435             btn.setFont(BUTTON_FONT);
436         }
437     }
438 
439     private static Font getMessageFont(Component owner) {
440         Font font = MESSAGE_FONT;
441         if (font == null) font = LABEL_FONT;
442         if (font == null) font = owner.getFont();
443         return font;
444     }
445 
446     private static Locale getLocaleForComponent(Component c) {
447         return (c == null) ? Locale.getDefault() : c.getLocale();
448     }
449 
450     public static void showMessageDialog(Component parentComponent,
451         Object message, Object details)
452     {
453         showMessageDialog(parentComponent, message, UIManager.getString(
454                           "OptionPane.messageDialogTitle",
455                           getLocaleForComponent(parentComponent)),
456                           JOptionPane.INFORMATION_MESSAGE, details);
457     }
458 
459     public static void showMessageDialog(Component parentComponent,
460         Object message, String title, int messageType, Object details)
461     {
462         showMessageDialog(parentComponent, message, title, messageType,
463                           iconForMessageType(messageType), details);
464     }
465 
466     public static void showMessageDialog(Component parentComponent,
467         Object message, String title, int messageType, Icon icon, Object details)
468     {
469         showOptionDialog(parentComponent, message, title, JOptionPane.DEFAULT_OPTION,
470                          messageType, icon, null, details);
471     }
472 
473     public static int showConfirmDialog(Component parentComponent,
474         Object message, Object details)
475     {
476         return showConfirmDialog(parentComponent, message,
477                                  UIManager.getString("OptionPane.titleText"),
478                                  JOptionPane.YES_NO_CANCEL_OPTION, details);
479     }
480 
481     public static int showConfirmDialog(Component parentComponent,
482         Object message, String title, int optionType, Object details)
483     {
484         return showConfirmDialog(parentComponent, message, title, optionType,
485                                  JOptionPane.QUESTION_MESSAGE, details);
486     }
487 
488     public static int showConfirmDialog(Component parentComponent,
489         Object message, String title, int optionType, int messageType,
490         Object details)
491     {
492         return showConfirmDialog(parentComponent, message, title, optionType,
493                                  messageType, iconForMessageType(messageType),
494                                  details);
495     }
496 
497     public static int showConfirmDialog(Component parentComponent,
498         Object message, String title, int optionType,
499         int messageType, Icon icon, Object details)
500     {
501         return showOptionDialog(parentComponent, message, title, optionType,
502                                 messageType, icon, null, details);
503     }
504 
505     public static int showOptionDialog(Component parentComponent,
506         Object message, String title, int optionType, int messageType,
507         Object[] options, Object details)
508     {
509         return showOptionDialog(parentComponent, message, title, optionType,
510                                 messageType, iconForMessageType(messageType),
511                                 options, details);
512     }
513 
514     public static int showOptionDialog(Component parentComponent,
515         Object message, String title, int optionType, int messageType,
516         Icon icon, Object[] options, Object details)
517     {
518         JDetailedMessageBox mbox = newInstance(parentComponent, title, message,
519                                                messageType, optionType, icon,
520                                                options, details);
521 
522         mbox.setInitialFocus();
523         mbox.show();
524         mbox.dispose();
525 
526         int selectedValue = mbox.getValue();
527         return selectedValue;
528     }
529 
530     private static class DetailViewport extends JViewport {
531         public Dimension getPreferredSize() {
532             Dimension d = super.getPreferredSize();
533             d.height = 150;
534             return d;
535         }
536     }
537 }