KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > swing > plaf > basic > BasicOptionPaneUI


1 /*
2  * @(#)BasicOptionPaneUI.java 1.58 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package javax.swing.plaf.basic;
9
10 import sun.swing.DefaultLookup;
11 import sun.swing.UIAction;
12 import javax.swing.border.Border JavaDoc;
13 import javax.swing.border.EmptyBorder JavaDoc;
14 import javax.swing.*;
15 import javax.swing.event.*;
16 import javax.swing.plaf.ActionMapUIResource JavaDoc;
17 import javax.swing.plaf.ComponentUI JavaDoc;
18 import javax.swing.plaf.OptionPaneUI JavaDoc;
19 import java.awt.*;
20 import java.awt.event.*;
21 import java.beans.PropertyChangeEvent JavaDoc;
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.util.Locale JavaDoc;
24 import java.security.AccessController JavaDoc;
25
26 import sun.security.action.GetPropertyAction;
27
28
29 /**
30  * Provides the basic look and feel for a <code>JOptionPane</code>.
31  * <code>BasicMessagePaneUI</code> provides a means to place an icon,
32  * message and buttons into a <code>Container</code>.
33  * Generally, the layout will look like:<p>
34  * <pre>
35  * ------------------
36  * | i | message |
37  * | c | message |
38  * | o | message |
39  * | n | message |
40  * ------------------
41  * | buttons |
42  * |________________|
43  * </pre>
44  * icon is an instance of <code>Icon</code> that is wrapped inside a
45  * <code>JLabel</code>. The message is an opaque object and is tested
46  * for the following: if the message is a <code>Component</code> it is
47  * added to the <code>Container</code>, if it is an <code>Icon</code>
48  * it is wrapped inside a <code>JLabel</code> and added to the
49  * <code>Container</code> otherwise it is wrapped inside a <code>JLabel</code>.
50  * <p>
51  * The above layout is used when the option pane's
52  * <code>ComponentOrientation</code> property is horizontal, left-to-right.
53  * The layout will be adjusted appropriately for other orientations.
54  * <p>
55  * The <code>Container</code>, message, icon, and buttons are all
56  * determined from abstract methods.
57  *
58  * @version 1.58 12/19/03
59  * @author James Gosling
60  * @author Scott Violet
61  * @author Amy Fowler
62  */

63 public class BasicOptionPaneUI extends OptionPaneUI JavaDoc {
64
65     public static final int MinimumWidth = 262;
66     public static final int MinimumHeight = 90;
67
68     private static String JavaDoc newline;
69
70     /**
71      * <code>JOptionPane</code> that the receiver is providing the
72      * look and feel for.
73      */

74     protected JOptionPane optionPane;
75
76     protected Dimension minimumSize;
77
78     /** JComponent provide for input if optionPane.getWantsInput() returns
79      * true. */

80     protected JComponent inputComponent;
81
82     /** Component to receive focus when messaged with selectInitialValue. */
83     protected Component initialFocusComponent;
84
85     /** This is set to true in validateComponent if a Component is contained
86      * in either the message or the buttons. */

87     protected boolean hasCustomComponents;
88
89     protected PropertyChangeListener JavaDoc propertyChangeListener;
90
91     private Handler handler;
92
93
94     static {
95     newline = (String JavaDoc)java.security.AccessController.doPrivileged(
96                                 new GetPropertyAction("line.separator"));
97         if (newline == null) {
98             newline = "\n";
99         }
100     }
101
102     static void loadActionMap(LazyActionMap JavaDoc map) {
103     map.put(new Actions(Actions.CLOSE));
104         BasicLookAndFeel.installAudioActionMap(map);
105     }
106
107
108
109     /**
110       * Creates a new BasicOptionPaneUI instance.
111       */

112     public static ComponentUI JavaDoc createUI(JComponent x) {
113     return new BasicOptionPaneUI JavaDoc();
114     }
115
116     /**
117       * Installs the receiver as the L&F for the passed in
118       * <code>JOptionPane</code>.
119       */

120     public void installUI(JComponent c) {
121     optionPane = (JOptionPane)c;
122         installDefaults();
123         optionPane.setLayout(createLayoutManager());
124     installComponents();
125         installListeners();
126         installKeyboardActions();
127     }
128
129     /**
130       * Removes the receiver from the L&F controller of the passed in split
131       * pane.
132       */

133     public void uninstallUI(JComponent c) {
134         uninstallComponents();
135         optionPane.setLayout(null);
136         uninstallKeyboardActions();
137         uninstallListeners();
138         uninstallDefaults();
139     optionPane = null;
140     }
141
142     protected void installDefaults() {
143         LookAndFeel.installColorsAndFont(optionPane, "OptionPane.background",
144                                          "OptionPane.foreground", "OptionPane.font");
145     LookAndFeel.installBorder(optionPane, "OptionPane.border");
146         minimumSize = UIManager.getDimension("OptionPane.minimumSize");
147         LookAndFeel.installProperty(optionPane, "opaque", Boolean.TRUE);
148     }
149
150     protected void uninstallDefaults() {
151     LookAndFeel.uninstallBorder(optionPane);
152     }
153
154     protected void installComponents() {
155     optionPane.add(createMessageArea());
156         
157         Container separator = createSeparator();
158         if (separator != null) {
159             optionPane.add(separator);
160         }
161     optionPane.add(createButtonArea());
162     optionPane.applyComponentOrientation(optionPane.getComponentOrientation());
163     }
164
165     protected void uninstallComponents() {
166     hasCustomComponents = false;
167         inputComponent = null;
168     initialFocusComponent = null;
169     optionPane.removeAll();
170     }
171
172     protected LayoutManager createLayoutManager() {
173         return new BoxLayout(optionPane, BoxLayout.Y_AXIS);
174     }
175
176     protected void installListeners() {
177         if ((propertyChangeListener = createPropertyChangeListener()) != null) {
178             optionPane.addPropertyChangeListener(propertyChangeListener);
179         }
180     }
181
182     protected void uninstallListeners() {
183         if (propertyChangeListener != null) {
184             optionPane.removePropertyChangeListener(propertyChangeListener);
185             propertyChangeListener = null;
186         }
187         handler = null;
188     }
189
190     protected PropertyChangeListener JavaDoc createPropertyChangeListener() {
191         return getHandler();
192     }
193
194     private Handler getHandler() {
195         if (handler == null) {
196             handler = new Handler();
197         }
198         return handler;
199     }
200
201     protected void installKeyboardActions() {
202     InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
203
204     SwingUtilities.replaceUIInputMap(optionPane, JComponent.
205                        WHEN_IN_FOCUSED_WINDOW, map);
206
207         LazyActionMap.installLazyActionMap(optionPane, BasicOptionPaneUI JavaDoc.class,
208                                            "OptionPane.actionMap");
209     }
210
211     protected void uninstallKeyboardActions() {
212     SwingUtilities.replaceUIInputMap(optionPane, JComponent.
213                        WHEN_IN_FOCUSED_WINDOW, null);
214     SwingUtilities.replaceUIActionMap(optionPane, null);
215     }
216
217     InputMap getInputMap(int condition) {
218     if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
219         Object JavaDoc[] bindings = (Object JavaDoc[])DefaultLookup.get(
220                              optionPane, this, "OptionPane.windowBindings");
221         if (bindings != null) {
222         return LookAndFeel.makeComponentInputMap(optionPane, bindings);
223         }
224     }
225     return null;
226     }
227
228     /**
229      * Returns the minimum size the option pane should be. Primarily
230      * provided for subclassers wishing to offer a different minimum size.
231      */

232     public Dimension getMinimumOptionPaneSize() {
233         if (minimumSize == null) {
234             return new Dimension(MinimumWidth, MinimumHeight);
235         }
236     return new Dimension(minimumSize.width,
237                  minimumSize.height);
238     }
239
240     /**
241      * If <code>c</code> is the <code>JOptionPane</code> the receiver
242      * is contained in, the preferred
243      * size that is returned is the maximum of the preferred size of
244      * the <code>LayoutManager</code> for the <code>JOptionPane</code>, and
245      * <code>getMinimumOptionPaneSize</code>.
246      */

247     public Dimension getPreferredSize(JComponent c) {
248     if ((JOptionPane)c == optionPane) {
249         Dimension ourMin = getMinimumOptionPaneSize();
250         LayoutManager lm = c.getLayout();
251
252         if (lm != null) {
253         Dimension lmSize = lm.preferredLayoutSize(c);
254
255         if (ourMin != null)
256             return new Dimension
257             (Math.max(lmSize.width, ourMin.width),
258              Math.max(lmSize.height, ourMin.height));
259         return lmSize;
260         }
261         return ourMin;
262     }
263     return null;
264     }
265
266     /**
267      * Messaged from installComponents to create a Container containing the
268      * body of the message. The icon is the created by calling
269      * <code>addIcon</code>.
270      */

271     protected Container createMessageArea() {
272         JPanel top = new JPanel();
273         Border JavaDoc topBorder = (Border JavaDoc)DefaultLookup.get(optionPane, this,
274                                              "OptionPane.messageAreaBorder");
275         if (topBorder != null) {
276             top.setBorder(topBorder);
277         }
278     top.setLayout(new BorderLayout());
279
280     /* Fill the body. */
281     Container body = new JPanel(new GridBagLayout());
282     Container realBody = new JPanel(new BorderLayout());
283
284         body.setName("OptionPane.body");
285         realBody.setName("OptionPane.realBody");
286
287     if (getIcon() != null) {
288             JPanel sep = new JPanel();
289             sep.setName("OptionPane.separator");
290             sep.setPreferredSize(new Dimension(15, 1));
291         realBody.add(sep, BorderLayout.BEFORE_LINE_BEGINS);
292     }
293     realBody.add(body, BorderLayout.CENTER);
294
295     GridBagConstraints cons = new GridBagConstraints();
296     cons.gridx = cons.gridy = 0;
297     cons.gridwidth = GridBagConstraints.REMAINDER;
298     cons.gridheight = 1;
299     cons.anchor = DefaultLookup.getInt(optionPane, this,
300                       "OptionPane.messageAnchor", GridBagConstraints.CENTER);
301     cons.insets = new Insets(0,0,3,0);
302
303     addMessageComponents(body, cons, getMessage(),
304               getMaxCharactersPerLineCount(), false);
305     top.add(realBody, BorderLayout.CENTER);
306
307     addIcon(top);
308     return top;
309     }
310
311     /**
312      * Creates the appropriate object to represent <code>msg</code> and
313      * places it into <code>container</code>. If <code>msg</code> is an
314      * instance of Component, it is added directly, if it is an Icon,
315      * a JLabel is created to represent it, otherwise a JLabel is
316      * created for the string, if <code>d</code> is an Object[], this
317      * method will be recursively invoked for the children.
318      * <code>internallyCreated</code> is true if Objc is an instance
319      * of Component and was created internally by this method (this is
320      * used to correctly set hasCustomComponents only if !internallyCreated).
321      */

322     protected void addMessageComponents(Container container,
323                      GridBagConstraints cons,
324                      Object JavaDoc msg, int maxll,
325                      boolean internallyCreated) {
326     if (msg == null) {
327         return;
328         }
329     if (msg instanceof Component) {
330             // To workaround problem where Gridbad will set child
331
// to its minimum size if its preferred size will not fit
332
// within allocated cells
333
if (msg instanceof JScrollPane || msg instanceof JPanel) {
334                 cons.fill = GridBagConstraints.BOTH;
335                 cons.weighty = 1;
336             } else {
337             cons.fill = GridBagConstraints.HORIZONTAL;
338             }
339         cons.weightx = 1;
340
341         container.add((Component) msg, cons);
342         cons.weightx = 0;
343             cons.weighty = 0;
344         cons.fill = GridBagConstraints.NONE;
345         cons.gridy++;
346         if (!internallyCreated) {
347         hasCustomComponents = true;
348             }
349
350     } else if (msg instanceof Object JavaDoc[]) {
351         Object JavaDoc [] msgs = (Object JavaDoc[]) msg;
352         for (int i = 0; i < msgs.length; i++) {
353         addMessageComponents(container, cons, msgs[i], maxll, false);
354             }
355
356     } else if (msg instanceof Icon) {
357         JLabel label = new JLabel( (Icon)msg, SwingConstants.CENTER );
358             configureMessageLabel(label);
359         addMessageComponents(container, cons, label, maxll, true);
360
361     } else {
362         String JavaDoc s = msg.toString();
363         int len = s.length();
364         if (len <= 0) {
365         return;
366             }
367         int nl = -1;
368         int nll = 0;
369
370         if ((nl = s.indexOf(newline)) >= 0) {
371         nll = newline.length();
372         } else if ((nl = s.indexOf("\r\n")) >= 0) {
373             nll = 2;
374         } else if ((nl = s.indexOf('\n')) >= 0) {
375             nll = 1;
376         }
377         if (nl >= 0) {
378         // break up newlines
379
if (nl == 0) {
380                     JPanel breakPanel = new JPanel() {
381                 public Dimension getPreferredSize() {
382                 Font f = getFont();
383                 
384                 if (f != null) {
385                 return new Dimension(1, f.getSize() + 2);
386                             }
387                 return new Dimension(0, 0);
388                 }
389                     };
390                     breakPanel.setName("OptionPane.break");
391             addMessageComponents(container, cons, breakPanel, maxll,
392                                          true);
393         } else {
394             addMessageComponents(container, cons, s.substring(0, nl),
395                       maxll, false);
396                 }
397         addMessageComponents(container, cons, s.substring(nl + nll), maxll,
398                   false);
399
400         } else if (len > maxll) {
401         Container c = Box.createVerticalBox();
402                 c.setName("OptionPane.verticalBox");
403         burstStringInto(c, s, maxll);
404         addMessageComponents(container, cons, c, maxll, true );
405
406         } else {
407             JLabel label;
408         label = new JLabel( s, JLabel.LEADING );
409                 label.setName("OptionPane.label");
410                 configureMessageLabel(label);
411         addMessageComponents(container, cons, label, maxll, true);
412         }
413     }
414     }
415
416     /**
417      * Returns the message to display from the JOptionPane the receiver is
418      * providing the look and feel for.
419      */

420     protected Object JavaDoc getMessage() {
421     inputComponent = null;
422     if (optionPane != null) {
423         if (optionPane.getWantsInput()) {
424         /* Create a user component to capture the input. If the
425            selectionValues are non null the component and there
426            are < 20 values it'll be a combobox, if non null and
427            >= 20, it'll be a list, otherwise it'll be a textfield. */

428         Object JavaDoc message = optionPane.getMessage();
429         Object JavaDoc[] sValues = optionPane.getSelectionValues();
430         Object JavaDoc inputValue = optionPane
431                                    .getInitialSelectionValue();
432         JComponent toAdd;
433
434         if (sValues != null) {
435             if (sValues.length < 20) {
436             JComboBox cBox = new JComboBox();
437
438                         cBox.setName("OptionPane.comboBox");
439             for(int counter = 0, maxCounter = sValues.length;
440                 counter < maxCounter; counter++) {
441                 cBox.addItem(sValues[counter]);
442                         }
443             if (inputValue != null) {
444                 cBox.setSelectedItem(inputValue);
445                         }
446             inputComponent = cBox;
447             toAdd = cBox;
448
449             } else {
450             JList list = new JList(sValues);
451             JScrollPane sp = new JScrollPane(list);
452
453                         sp.setName("OptionPane.scrollPane");
454                         list.setName("OptionPane.list");
455             list.setVisibleRowCount(10);
456             list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
457             if(inputValue != null)
458                 list.setSelectedValue(inputValue, true);
459             list.addMouseListener(getHandler());
460             toAdd = sp;
461             inputComponent = list;
462             }
463
464         } else {
465             MultiplexingTextField tf = new MultiplexingTextField(20);
466
467                     tf.setName("OptionPane.textField");
468                     tf.setKeyStrokes(new KeyStroke[] {
469                                      KeyStroke.getKeyStroke("ENTER") } );
470             if (inputValue != null) {
471                         String JavaDoc inputString = inputValue.toString();
472             tf.setText(inputString);
473                         tf.setSelectionStart(0);
474                         tf.setSelectionEnd(inputString.length());
475                     }
476             tf.addActionListener(getHandler());
477             toAdd = inputComponent = tf;
478         }
479
480         Object JavaDoc[] newMessage;
481
482         if (message == null) {
483             newMessage = new Object JavaDoc[1];
484             newMessage[0] = toAdd;
485         
486         } else {
487             newMessage = new Object JavaDoc[2];
488             newMessage[0] = message;
489             newMessage[1] = toAdd;
490         }
491         return newMessage;
492         }
493         return optionPane.getMessage();
494     }
495     return null;
496     }
497
498     /**
499      * Creates and adds a JLabel representing the icon returned from
500      * <code>getIcon</code> to <code>top</code>. This is messaged from
501      * <code>createMessageArea</code>
502      */

503     protected void addIcon(Container top) {
504     /* Create the icon. */
505     Icon sideIcon = getIcon();
506
507     if (sideIcon != null) {
508         JLabel iconLabel = new JLabel(sideIcon);
509
510             iconLabel.setName("OptionPane.iconLabel");
511         iconLabel.setVerticalAlignment(SwingConstants.TOP);
512         top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS);
513     }
514     }
515
516     /**
517      * Returns the icon from the JOptionPane the receiver is providing
518      * the look and feel for, or the default icon as returned from
519      * <code>getDefaultIcon</code>.
520      */

521     protected Icon getIcon() {
522     Icon mIcon = (optionPane == null ? null : optionPane.getIcon());
523
524     if(mIcon == null && optionPane != null)
525         mIcon = getIconForType(optionPane.getMessageType());
526     return mIcon;
527     }
528
529     /**
530      * Returns the icon to use for the passed in type.
531      */

532     protected Icon getIconForType(int messageType) {
533     if(messageType < 0 || messageType > 3)
534         return null;
535         String JavaDoc propertyName = null;
536     switch(messageType) {
537     case 0:
538         propertyName = "OptionPane.errorIcon";
539             break;
540     case 1:
541         propertyName = "OptionPane.informationIcon";
542             break;
543     case 2:
544         propertyName = "OptionPane.warningIcon";
545             break;
546     case 3:
547         propertyName = "OptionPane.questionIcon";
548             break;
549     }
550         if (propertyName != null) {
551             return (Icon)DefaultLookup.get(optionPane, this, propertyName);
552     }
553     return null;
554     }
555
556     /**
557      * Returns the maximum number of characters to place on a line.
558      */

559     protected int getMaxCharactersPerLineCount() {
560     return optionPane.getMaxCharactersPerLineCount();
561     }
562
563    /**
564      * Recursively creates new JLabel instances to represent <code>d</code>.
565      * Each JLabel instance is added to <code>c</code>.
566      */

567     protected void burstStringInto(Container c, String JavaDoc d, int maxll) {
568     // Primitive line wrapping
569
int len = d.length();
570     if (len <= 0)
571         return;
572     if (len > maxll) {
573         int p = d.lastIndexOf(' ', maxll);
574         if (p <= 0)
575         p = d.indexOf(' ', maxll);
576         if (p > 0 && p < len) {
577         burstStringInto(c, d.substring(0, p), maxll);
578         burstStringInto(c, d.substring(p + 1), maxll);
579         return;
580         }
581     }
582     JLabel label = new JLabel(d, JLabel.LEFT);
583         label.setName("OptionPane.label");
584         configureMessageLabel(label);
585     c.add(label);
586     }
587
588     protected Container createSeparator() {
589         return null;
590     }
591
592     /**
593      * Creates and returns a Container containing the buttons. The buttons
594      * are created by calling <code>getButtons</code>.
595      */

596     protected Container createButtonArea() {
597         JPanel bottom = new JPanel();
598         Border JavaDoc border = (Border JavaDoc)DefaultLookup.get(optionPane, this,
599                                           "OptionPane.buttonAreaBorder");
600         bottom.setName("OptionPane.buttonArea");
601         if (border != null) {
602             bottom.setBorder(border);
603         }
604     bottom.setLayout(new ButtonAreaLayout(
605            DefaultLookup.getBoolean(optionPane, this,
606                                     "OptionPane.sameSizeButtons", true),
607            DefaultLookup.getInt(optionPane, this, "OptionPane.buttonPadding",
608                                 6),
609            DefaultLookup.getInt(optionPane, this,
610                         "OptionPane.buttonOrientation", SwingConstants.CENTER),
611            DefaultLookup.getBoolean(optionPane, this, "OptionPane.isYesLast",
612                                     false)));
613     addButtonComponents(bottom, getButtons(), getInitialValueIndex());
614     return bottom;
615     }
616
617     /**
618      * Creates the appropriate object to represent each of the objects in
619      * <code>buttons</code> and adds it to <code>container</code>. This
620      * differs from addMessageComponents in that it will recurse on
621      * <code>buttons</code> and that if button is not a Component
622      * it will create an instance of JButton.
623      */

624     protected void addButtonComponents(Container container, Object JavaDoc[] buttons,
625                  int initialIndex) {
626     if (buttons != null && buttons.length > 0) {
627         boolean sizeButtonsToSame = getSizeButtonsToSameWidth();
628         boolean createdAll = true;
629         int numButtons = buttons.length;
630         JButton[] createdButtons = null;
631         int maxWidth = 0;
632
633         if (sizeButtonsToSame) {
634         createdButtons = new JButton[numButtons];
635             }
636
637         for(int counter = 0; counter < numButtons; counter++) {
638         Object JavaDoc button = buttons[counter];
639         Component newComponent;
640
641         if (button instanceof Component) {
642             createdAll = false;
643             newComponent = (Component)button;
644             container.add(newComponent);
645             hasCustomComponents = true;
646         
647         } else {
648             JButton aButton;
649
650                     if (button instanceof ButtonFactory) {
651                         aButton = ((ButtonFactory)button).createButton();
652                     }
653             else if (button instanceof Icon)
654             aButton = new JButton((Icon)button);
655             else
656             aButton = new JButton(button.toString());
657
658                     aButton.setName("OptionPane.button");
659             aButton.setMultiClickThreshhold(DefaultLookup.getInt(
660                           optionPane, this, "OptionPane.buttonClickThreshhold",
661                           0));
662                     configureButton(aButton);
663
664             container.add(aButton);
665
666                     ActionListener buttonListener = createButtonActionListener(counter);
667                     if (buttonListener != null) {
668                         aButton.addActionListener(buttonListener);
669                     }
670             newComponent = aButton;
671         }
672         if (sizeButtonsToSame && createdAll &&
673            (newComponent instanceof JButton)) {
674             createdButtons[counter] = (JButton)newComponent;
675             maxWidth = Math.max(maxWidth,
676                     newComponent.getMinimumSize().width);
677         }
678         if (counter == initialIndex) {
679             initialFocusComponent = newComponent;
680                     if (initialFocusComponent instanceof JButton) {
681                         JButton defaultB = (JButton)initialFocusComponent;
682                         defaultB.addAncestorListener(new AncestorListener() {
683                            public void ancestorAdded(AncestorEvent e) {
684                                JButton defaultButton = (JButton)e.getComponent();
685                                JRootPane root = SwingUtilities.getRootPane(defaultButton);
686                                if (root != null) {
687                                    root.setDefaultButton(defaultButton);
688                                }
689                            }
690                            public void ancestorRemoved(AncestorEvent event) {}
691                            public void ancestorMoved(AncestorEvent event) {}
692                         });
693                     }
694         }
695         }
696         ((ButtonAreaLayout)container.getLayout()).
697                       setSyncAllWidths((sizeButtonsToSame && createdAll));
698         /* Set the padding, windows seems to use 8 if <= 2 components,
699            otherwise 4 is used. It may actually just be the size of the
700            buttons is always the same, not sure. */

701         if (DefaultLookup.getBoolean(optionPane, this,
702                    "OptionPane.setButtonMargin", true) && sizeButtonsToSame &&
703                    createdAll) {
704         JButton aButton;
705         int padSize;
706
707         padSize = (numButtons <= 2? 8 : 4);
708
709         for(int counter = 0; counter < numButtons; counter++) {
710             aButton = createdButtons[counter];
711             aButton.setMargin(new Insets(2, padSize, 2, padSize));
712         }
713         }
714     }
715     }
716
717     protected ActionListener createButtonActionListener(int buttonIndex) {
718         return new ButtonActionListener(buttonIndex);
719     }
720
721     /**
722      * Returns the buttons to display from the JOptionPane the receiver is
723      * providing the look and feel for. If the JOptionPane has options
724      * set, they will be provided, otherwise if the optionType is
725      * YES_NO_OPTION, yesNoOptions is returned, if the type is
726      * YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise
727      * defaultButtons are returned.
728      */

729     protected Object JavaDoc[] getButtons() {
730     if (optionPane != null) {
731         Object JavaDoc[] suppliedOptions = optionPane.getOptions();
732
733         if (suppliedOptions == null) {
734                 Object JavaDoc[] defaultOptions;
735         int type = optionPane.getOptionType();
736                 Locale JavaDoc l = optionPane.getLocale();
737         if (type == JOptionPane.YES_NO_OPTION) {
738                     defaultOptions = new ButtonFactory[2];
739                     defaultOptions[0] = new ButtonFactory(
740                         UIManager.getString("OptionPane.yesButtonText", l),
741                         getMnemonic("OptionPane.yesButtonMnemonic", l),
742                         (Icon)DefaultLookup.get(optionPane, this,
743                                           "OptionPane.yesIcon"));
744                     defaultOptions[1] = new ButtonFactory(
745                         UIManager.getString("OptionPane.noButtonText", l),
746                         getMnemonic("OptionPane.noButtonMnemonic", l),
747                         (Icon)DefaultLookup.get(optionPane, this,
748                                           "OptionPane.noIcon"));
749         } else if (type == JOptionPane.YES_NO_CANCEL_OPTION) {
750                     defaultOptions = new ButtonFactory[3];
751                     defaultOptions[0] = new ButtonFactory(
752                         UIManager.getString("OptionPane.yesButtonText", l),
753                         getMnemonic("OptionPane.yesButtonMnemonic", l),
754                         (Icon)DefaultLookup.get(optionPane, this,
755                                           "OptionPane.yesIcon"));
756                     defaultOptions[1] = new ButtonFactory(
757                         UIManager.getString("OptionPane.noButtonText",l),
758                         getMnemonic("OptionPane.noButtonMnemonic", l),
759                         (Icon)DefaultLookup.get(optionPane, this,
760                                           "OptionPane.noIcon"));
761                     defaultOptions[2] = new ButtonFactory(
762                         UIManager.getString("OptionPane.cancelButtonText",l),
763                         getMnemonic("OptionPane.cancelButtonMnemonic", l),
764                         (Icon)DefaultLookup.get(optionPane, this,
765                                           "OptionPane.cancelIcon"));
766         } else if (type == JOptionPane.OK_CANCEL_OPTION) {
767                     defaultOptions = new ButtonFactory[2];
768                     defaultOptions[0] = new ButtonFactory(
769                         UIManager.getString("OptionPane.okButtonText",l),
770                         getMnemonic("OptionPane.okButtonMnemonic", l),
771                         (Icon)DefaultLookup.get(optionPane, this,
772                                           "OptionPane.okIcon"));
773                     defaultOptions[1] = new ButtonFactory(
774                         UIManager.getString("OptionPane.cancelButtonText",l),
775                         getMnemonic("OptionPane.cancelButtonMnemonic", l),
776                         (Icon)DefaultLookup.get(optionPane, this,
777                                           "OptionPane.cancelIcon"));
778         } else {
779                     defaultOptions = new ButtonFactory[1];
780                     defaultOptions[0] = new ButtonFactory(
781                         UIManager.getString("OptionPane.okButtonText",l),
782                         getMnemonic("OptionPane.okButtonMnemonic", l),
783                         (Icon)DefaultLookup.get(optionPane, this,
784                                           "OptionPane.okIcon"));
785                 }
786                 return defaultOptions;
787                 
788         }
789         return suppliedOptions;
790     }
791     return null;
792     }
793
794     private int getMnemonic(String JavaDoc key, Locale JavaDoc l) {
795         String JavaDoc value = (String JavaDoc)UIManager.get(key, l);
796
797         if (value == null) {
798             return 0;
799         }
800         try {
801             return Integer.parseInt(value);
802         }
803         catch (NumberFormatException JavaDoc nfe) { }
804         return 0;
805     }
806
807     /**
808      * Returns true, basic L&F wants all the buttons to have the same
809      * width.
810      */

811     protected boolean getSizeButtonsToSameWidth() {
812     return true;
813     }
814
815     /**
816      * Returns the initial index into the buttons to select. The index
817      * is calculated from the initial value from the JOptionPane and
818      * options of the JOptionPane or 0.
819      */

820     protected int getInitialValueIndex() {
821     if (optionPane != null) {
822         Object JavaDoc iv = optionPane.getInitialValue();
823         Object JavaDoc[] options = optionPane.getOptions();
824
825         if(options == null) {
826         return 0;
827         }
828         else if(iv != null) {
829         for(int counter = options.length - 1; counter >= 0; counter--){
830             if(options[counter].equals(iv))
831             return counter;
832         }
833         }
834     }
835     return -1;
836     }
837
838     /**
839      * Sets the input value in the option pane the receiver is providing
840      * the look and feel for based on the value in the inputComponent.
841      */

842     protected void resetInputValue() {
843     if(inputComponent != null && (inputComponent instanceof JTextField)) {
844         optionPane.setInputValue(((JTextField)inputComponent).getText());
845
846     } else if(inputComponent != null &&
847                   (inputComponent instanceof JComboBox)) {
848         optionPane.setInputValue(((JComboBox)inputComponent)
849                      .getSelectedItem());
850     } else if(inputComponent != null) {
851         optionPane.setInputValue(((JList)inputComponent)
852                      .getSelectedValue());
853         }
854     }
855
856
857     /**
858      * If inputComponent is non-null, the focus is requested on that,
859      * otherwise request focus on the default value
860      */

861     public void selectInitialValue(JOptionPane op) {
862     if (inputComponent != null)
863         inputComponent.requestFocus();
864     else {
865         if (initialFocusComponent != null)
866             initialFocusComponent.requestFocus();
867
868             if (initialFocusComponent instanceof JButton) {
869                 JRootPane root = SwingUtilities.getRootPane(initialFocusComponent);
870                 if (root != null) {
871                     root.setDefaultButton((JButton)initialFocusComponent);
872                 }
873             }
874         }
875     }
876
877     /**
878      * Returns true if in the last call to validateComponent the message
879      * or buttons contained a subclass of Component.
880      */

881     public boolean containsCustomComponents(JOptionPane op) {
882     return hasCustomComponents;
883     }
884
885
886     /**
887      * <code>ButtonAreaLayout</code> behaves in a similar manner to
888      * <code>FlowLayout</code>. It lays out all components from left to
889      * right. If <code>syncAllWidths</code> is true, the widths of each
890      * component will be set to the largest preferred size width.
891      *
892      * This inner class is marked &quot;public&quot; due to a compiler bug.
893      * This class should be treated as a &quot;protected&quot; inner class.
894      * Instantiate it only within subclasses of BasicOptionPaneUI.
895      */

896     public static class ButtonAreaLayout implements LayoutManager {
897     protected boolean syncAllWidths;
898     protected int padding;
899         /** If true, children are lumped together in parent. */
900     protected boolean centersChildren;
901         private int orientation;
902         private boolean reverseButtons;
903         /**
904          * Indicates whether or not centersChildren should be used vs
905          * the orientation. This is done for backward compatability
906          * for subclassers.
907          */

908         private boolean useOrientation;
909
910     public ButtonAreaLayout(boolean syncAllWidths, int padding) {
911         this.syncAllWidths = syncAllWidths;
912         this.padding = padding;
913         centersChildren = true;
914             useOrientation = false;
915     }
916
917         ButtonAreaLayout(boolean syncAllSizes, int padding, int orientation,
918                          boolean reverseButtons) {
919             this(syncAllSizes, padding);
920             useOrientation = true;
921             this.orientation = orientation;
922             this.reverseButtons = reverseButtons;
923         }
924
925     public void setSyncAllWidths(boolean newValue) {
926         syncAllWidths = newValue;
927     }
928
929     public boolean getSyncAllWidths() {
930         return syncAllWidths;
931     }
932
933     public void setPadding(int newPadding) {
934         this.padding = newPadding;
935     }
936
937     public int getPadding() {
938         return padding;
939     }
940
941         public void setCentersChildren(boolean newValue) {
942         centersChildren = newValue;
943             useOrientation = false;
944     }
945
946         public boolean getCentersChildren() {
947         return centersChildren;
948     }
949
950         private int getOrientation(Container container) {
951             if (!useOrientation) {
952                 return SwingConstants.CENTER;
953             }
954             if (container.getComponentOrientation().isLeftToRight()) {
955                 return orientation;
956             }
957             switch (orientation) {
958             case SwingConstants.LEFT:
959                 return SwingConstants.RIGHT;
960             case SwingConstants.RIGHT:
961                 return SwingConstants.LEFT;
962             case SwingConstants.CENTER:
963                 return SwingConstants.CENTER;
964             }
965             return SwingConstants.LEFT;
966         }
967
968     public void addLayoutComponent(String JavaDoc string, Component comp) {
969     }
970
971     public void layoutContainer(Container container) {
972         Component[] children = container.getComponents();
973
974         if(children != null && children.length > 0) {
975         int numChildren = children.length;
976         Insets insets = container.getInsets();
977                 int maxWidth = 0;
978                 int maxHeight = 0;
979                 int totalButtonWidth = 0;
980                 int x = 0;
981                 int xOffset = 0;
982                 boolean ltr = container.getComponentOrientation().
983                                         isLeftToRight();
984                 boolean reverse = (ltr) ? reverseButtons : !reverseButtons;
985
986                 for(int counter = 0; counter < numChildren; counter++) {
987                     Dimension pref = children[counter].getPreferredSize();
988                     maxWidth = Math.max(maxWidth, pref.width);
989                     maxHeight = Math.max(maxHeight, pref.height);
990                     totalButtonWidth += pref.width;
991                 }
992                 if (getSyncAllWidths()) {
993                     totalButtonWidth = maxWidth * numChildren;
994                 }
995                 totalButtonWidth += (numChildren - 1) * padding;
996
997                 switch (getOrientation(container)) {
998                 case SwingConstants.LEFT:
999                     x = insets.left;
1000                    break;
1001                case SwingConstants.RIGHT:
1002                    x = container.getWidth() - insets.right - totalButtonWidth;
1003                    break;
1004                case SwingConstants.CENTER:
1005                    if (getCentersChildren() || numChildren < 2) {
1006                        x = (container.getWidth() - totalButtonWidth) / 2;
1007                    }
1008                    else {
1009                        x = insets.left;
1010                        if (getSyncAllWidths()) {
1011                            xOffset = (container.getWidth() - insets.left -
1012                                       insets.right - totalButtonWidth) /
1013                                (numChildren - 1) + maxWidth;
1014                        }
1015                        else {
1016                            xOffset = (container.getWidth() - insets.left -
1017                                       insets.right - totalButtonWidth) /
1018                                      (numChildren - 1);
1019                        }
1020                    }
1021                    break;
1022                }
1023
1024                for (int counter = 0; counter < numChildren; counter++) {
1025                    int index = (reverse) ? numChildren - counter - 1 :
1026                                counter;
1027                    Dimension pref = children[index].getPreferredSize();
1028
1029                    if (getSyncAllWidths()) {
1030                        children[index].setBounds(x, insets.top,
1031                                                  maxWidth, maxHeight);
1032                    }
1033                    else {
1034                        children[index].setBounds(x, insets.top, pref.width,
1035                                                  pref.height);
1036                    }
1037                    if (xOffset != 0) {
1038                        x += xOffset;
1039                    }
1040                    else {
1041                        x += children[index].getWidth() + padding;
1042                    }
1043                }
1044        }
1045    }
1046
1047    public Dimension minimumLayoutSize(Container c) {
1048        if(c != null) {
1049        Component[] children = c.getComponents();
1050
1051        if(children != null && children.length > 0) {
1052            Dimension aSize;
1053            int numChildren = children.length;
1054            int height = 0;
1055            Insets cInsets = c.getInsets();
1056            int extraHeight = cInsets.top + cInsets.bottom;
1057            int extraWidth = cInsets.left + cInsets.right;
1058
1059            if (syncAllWidths) {
1060            int maxWidth = 0;
1061
1062            for(int counter = 0; counter < numChildren; counter++){
1063                aSize = children[counter].getPreferredSize();
1064                height = Math.max(height, aSize.height);
1065                maxWidth = Math.max(maxWidth, aSize.width);
1066            }
1067            return new Dimension(extraWidth + (maxWidth * numChildren) +
1068                         (numChildren - 1) * padding,
1069                         extraHeight + height);
1070            }
1071            else {
1072            int totalWidth = 0;
1073
1074            for(int counter = 0; counter < numChildren; counter++){
1075                aSize = children[counter].getPreferredSize();
1076                height = Math.max(height, aSize.height);
1077                totalWidth += aSize.width;
1078            }
1079            totalWidth += ((numChildren - 1) * padding);
1080            return new Dimension(extraWidth + totalWidth, extraHeight + height);
1081            }
1082        }
1083        }
1084        return new Dimension(0, 0);
1085    }
1086
1087    public Dimension preferredLayoutSize(Container c) {
1088        return minimumLayoutSize(c);
1089    }
1090
1091    public void removeLayoutComponent(Component c) { }
1092    }
1093
1094
1095    /**
1096     * This inner class is marked &quot;public&quot; due to a compiler bug.
1097     * This class should be treated as a &quot;protected&quot; inner class.
1098     * Instantiate it only within subclasses of BasicOptionPaneUI.
1099     */

1100    public class PropertyChangeHandler implements PropertyChangeListener JavaDoc {
1101        /**
1102         * If the source of the PropertyChangeEvent <code>e</code> equals the
1103         * optionPane and is one of the ICON_PROPERTY, MESSAGE_PROPERTY,
1104         * OPTIONS_PROPERTY or INITIAL_VALUE_PROPERTY,
1105         * validateComponent is invoked.
1106         */

1107        public void propertyChange(PropertyChangeEvent JavaDoc e) {
1108            getHandler().propertyChange(e);
1109    }
1110    }
1111
1112    /**
1113     * Configures any necessary colors/fonts for the specified label
1114     * used representing the message.
1115     */

1116    private void configureMessageLabel(JLabel label) {
1117        Color color = (Color)DefaultLookup.get(optionPane, this,
1118                                               "OptionPane.messageForeground");
1119        if (color != null) {
1120            label.setForeground(color);
1121        }
1122        Font messageFont = (Font)DefaultLookup.get(optionPane, this,
1123                                                   "OptionPane.messageFont");
1124        if (messageFont != null) {
1125            label.setFont(messageFont);
1126        }
1127    }
1128
1129    /**
1130     * Configures any necessary colors/fonts for the specified button
1131     * used representing the button portion of the optionpane.
1132     */

1133    private void configureButton(JButton button) {
1134        Font buttonFont = (Font)DefaultLookup.get(optionPane, this,
1135                                            "OptionPane.buttonFont");
1136        if (buttonFont != null) {
1137            button.setFont(buttonFont);
1138        }
1139    }
1140
1141    /**
1142     * This inner class is marked &quot;public&quot; due to a compiler bug.
1143     * This class should be treated as a &quot;protected&quot; inner class.
1144     * Instantiate it only within subclasses of BasicOptionPaneUI.
1145     */

1146    public class ButtonActionListener implements ActionListener {
1147        protected int buttonIndex;
1148
1149        public ButtonActionListener(int buttonIndex) {
1150            this.buttonIndex = buttonIndex;
1151        }
1152
1153        public void actionPerformed(ActionEvent e) {
1154        if (optionPane != null) {
1155            int optionType = optionPane.getOptionType();
1156            Object JavaDoc[] options = optionPane.getOptions();
1157
1158                /* If the option pane takes input, then store the input value
1159                 * if custom options were specified, if the option type is
1160                 * DEFAULT_OPTION, OR if option type is set to a predefined
1161                 * one and the user chose the affirmative answer.
1162                 */

1163        if (inputComponent != null) {
1164                    if (options != null ||
1165                        optionType == JOptionPane.DEFAULT_OPTION ||
1166                    ((optionType == JOptionPane.YES_NO_OPTION ||
1167                 optionType == JOptionPane.YES_NO_CANCEL_OPTION ||
1168                 optionType == JOptionPane.OK_CANCEL_OPTION) &&
1169                 buttonIndex == 0)) {
1170                resetInputValue();
1171                    }
1172                }
1173            if (options == null) {
1174            if (optionType == JOptionPane.OK_CANCEL_OPTION &&
1175                        buttonIndex == 1) {
1176                optionPane.setValue(new Integer JavaDoc(2));
1177                    
1178            } else {
1179                optionPane.setValue(new Integer JavaDoc(buttonIndex));
1180                    }
1181            } else {
1182            optionPane.setValue(options[buttonIndex]);
1183                }
1184        }
1185        }
1186    }
1187
1188
1189    private class Handler implements ActionListener, MouseListener,
1190                                     PropertyChangeListener JavaDoc {
1191        //
1192
// ActionListener
1193
//
1194
public void actionPerformed(ActionEvent e) {
1195        optionPane.setInputValue(((JTextField)e.getSource()).getText());
1196    }
1197
1198
1199        //
1200
// MouseListener
1201
//
1202
public void mouseClicked(MouseEvent e) {
1203        }
1204
1205        public void mouseReleased(MouseEvent e) {
1206        }
1207
1208        public void mouseEntered(MouseEvent e) {
1209        }
1210
1211        public void mouseExited(MouseEvent e) {
1212        }
1213
1214    public void mousePressed(MouseEvent e) {
1215        if (e.getClickCount() == 2) {
1216        JList list = (JList)e.getSource();
1217        int index = list.locationToIndex(e.getPoint());
1218
1219        optionPane.setInputValue(list.getModel().getElementAt(index));
1220        }
1221    }
1222
1223        //
1224
// PropertyChangeListener
1225
//
1226
public void propertyChange(PropertyChangeEvent JavaDoc e) {
1227        if(e.getSource() == optionPane) {
1228        // Option Pane Auditory Cue Activation
1229
// only respond to "ancestor" changes
1230
// the idea being that a JOptionPane gets a JDialog when it is
1231
// set to appear and loses it's JDialog when it is dismissed.
1232
if ("ancestor" == e.getPropertyName()) {
1233            JOptionPane op = (JOptionPane)e.getSource();
1234            boolean isComingUp;
1235            
1236            // if the old value is null, then the JOptionPane is being
1237
// created since it didn't previously have an ancestor.
1238
if (e.getOldValue() == null) {
1239            isComingUp = true;
1240            } else {
1241            isComingUp = false;
1242            }
1243            
1244            // figure out what to do based on the message type
1245
switch (op.getMessageType()) {
1246            case JOptionPane.PLAIN_MESSAGE:
1247            if (isComingUp) {
1248                            BasicLookAndFeel.playSound(optionPane,
1249                                               "OptionPane.informationSound");
1250            }
1251            break;
1252            case JOptionPane.QUESTION_MESSAGE:
1253            if (isComingUp) {
1254                            BasicLookAndFeel.playSound(optionPane,
1255                                             "OptionPane.questionSound");
1256            }
1257            break;
1258            case JOptionPane.INFORMATION_MESSAGE:
1259            if (isComingUp) {
1260                            BasicLookAndFeel.playSound(optionPane,
1261                                             "OptionPane.informationSound");
1262            }
1263            break;
1264            case JOptionPane.WARNING_MESSAGE:
1265            if (isComingUp) {
1266                            BasicLookAndFeel.playSound(optionPane,
1267                                             "OptionPane.warningSound");
1268            }
1269            break;
1270            case JOptionPane.ERROR_MESSAGE:
1271            if (isComingUp) {
1272                            BasicLookAndFeel.playSound(optionPane,
1273                                 "OptionPane.errorSound");
1274            }
1275            break;
1276            default:
1277            System.err.println("Undefined JOptionPane type: " +
1278                       op.getMessageType());
1279            break;
1280            }
1281        }
1282        // Visual activity
1283
String JavaDoc changeName = e.getPropertyName();
1284
1285            if(changeName == JOptionPane.OPTIONS_PROPERTY ||
1286                   changeName == JOptionPane.INITIAL_VALUE_PROPERTY ||
1287               changeName == JOptionPane.ICON_PROPERTY ||
1288               changeName == JOptionPane.MESSAGE_TYPE_PROPERTY ||
1289               changeName == JOptionPane.OPTION_TYPE_PROPERTY ||
1290               changeName == JOptionPane.MESSAGE_PROPERTY ||
1291               changeName == JOptionPane.SELECTION_VALUES_PROPERTY ||
1292               changeName == JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY ||
1293               changeName == JOptionPane.WANTS_INPUT_PROPERTY) {
1294                   uninstallComponents();
1295                   installComponents();
1296                   optionPane.validate();
1297                }
1298        else if (changeName == "componentOrientation") {
1299            ComponentOrientation o = (ComponentOrientation)e.getNewValue();
1300            JOptionPane op = (JOptionPane)e.getSource();
1301            if (o != (ComponentOrientation)e.getOldValue()) {
1302            op.applyComponentOrientation(o);
1303            }
1304        }
1305            }
1306        }
1307    }
1308
1309
1310    //
1311
// Classes used when optionPane.getWantsInput returns true.
1312
//
1313

1314    /**
1315     * A JTextField that allows you to specify an array of KeyStrokes that
1316     * that will have their bindings processed regardless of whether or
1317     * not they are registered on the JTextField. This is used as we really
1318     * want the ActionListener to be notified so that we can push the
1319     * change to the JOptionPane, but we also want additional bindings
1320     * (those of the JRootPane) to be processed as well.
1321     */

1322    private static class MultiplexingTextField extends JTextField {
1323        private KeyStroke[] strokes;
1324
1325        MultiplexingTextField(int cols) {
1326            super(cols);
1327        }
1328
1329        /**
1330         * Sets the KeyStrokes that will be additional processed for
1331         * ancestor bindings.
1332         */

1333        void setKeyStrokes(KeyStroke[] strokes) {
1334            this.strokes = strokes;
1335        }
1336
1337        protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
1338                                            int condition, boolean pressed) {
1339            boolean processed = super.processKeyBinding(ks, e, condition,
1340                                                        pressed);
1341
1342            if (processed && condition != JComponent.WHEN_IN_FOCUSED_WINDOW) {
1343                for (int counter = strokes.length - 1; counter >= 0;
1344                         counter--) {
1345                    if (strokes[counter].equals(ks)) {
1346                        // Returning false will allow further processing
1347
// of the bindings, eg our parent Containers will get a
1348
// crack at them.
1349
return false;
1350                    }
1351                }
1352            }
1353            return processed;
1354        }
1355    }
1356
1357
1358
1359    /**
1360     * Registered in the ActionMap. Sets the value of the option pane
1361     * to <code>JOptionPane.CLOSED_OPTION</code>.
1362     */

1363    private static class Actions extends UIAction {
1364        private static final String JavaDoc CLOSE = "close";
1365
1366        Actions(String JavaDoc key) {
1367            super(key);
1368        }
1369
1370    public void actionPerformed(ActionEvent e) {
1371            if (getName() == CLOSE) {
1372                JOptionPane optionPane = (JOptionPane)e.getSource();
1373
1374                optionPane.setValue(new Integer JavaDoc(JOptionPane.CLOSED_OPTION));
1375            }
1376    }
1377    }
1378
1379
1380    /**
1381     * This class is used to create the default buttons. This indirection is
1382     * used so that addButtonComponents can tell which Buttons were created
1383     * by us vs subclassers or from the JOptionPane itself.
1384     */

1385    private static class ButtonFactory {
1386        private String JavaDoc text;
1387        private int mnemonic;
1388        private Icon icon;
1389
1390        ButtonFactory(String JavaDoc text, int mnemonic, Icon icon) {
1391            this.text = text;
1392            this.mnemonic = mnemonic;
1393            this.icon = icon;
1394        }
1395
1396        JButton createButton() {
1397            JButton button = new JButton(text);
1398            if (icon != null) {
1399                button.setIcon(icon);
1400            }
1401            if (mnemonic != 0) {
1402                button.setMnemonic(mnemonic);
1403            }
1404            return button;
1405        }
1406    }
1407}
1408
Popular Tags