1 /* BasicOptionPaneUI.java --
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax
.swing
.plaf
.basic
;
41 import java
.awt
.BorderLayout
;
42 import java
.awt
.Color
;
43 import java
.awt
.Component
;
44 import java
.awt
.Container
;
45 import java
.awt
.Dimension
;
46 import java
.awt
.Graphics
;
47 import java
.awt
.GridBagConstraints
;
48 import java
.awt
.GridBagLayout
;
49 import java
.awt
.Insets
;
50 import java
.awt
.LayoutManager
;
51 import java
.awt
.Polygon
;
52 import java
.awt
.Window
;
53 import java
.awt
.event
.ActionEvent
;
54 import java
.awt
.event
.ActionListener
;
55 import java
.beans
.PropertyChangeEvent
;
56 import java
.beans
.PropertyChangeListener
;
57 import java
.beans
.PropertyVetoException
;
59 import javax
.swing
.BorderFactory
;
60 import javax
.swing
.Box
;
61 import javax
.swing
.BoxLayout
;
62 import javax
.swing
.Icon
;
63 import javax
.swing
.JButton
;
64 import javax
.swing
.JComboBox
;
65 import javax
.swing
.JComponent
;
66 import javax
.swing
.JDialog
;
67 import javax
.swing
.JInternalFrame
;
68 import javax
.swing
.JLabel
;
69 import javax
.swing
.JList
;
70 import javax
.swing
.JOptionPane
;
71 import javax
.swing
.JPanel
;
72 import javax
.swing
.JTextField
;
73 import javax
.swing
.LookAndFeel
;
74 import javax
.swing
.SwingUtilities
;
75 import javax
.swing
.UIManager
;
76 import javax
.swing
.border
.Border
;
77 import javax
.swing
.plaf
.ComponentUI
;
78 import javax
.swing
.plaf
.OptionPaneUI
;
81 * This class is the UI delegate for JOptionPane in the Basic Look and Feel.
83 public class BasicOptionPaneUI
extends OptionPaneUI
86 * This is a helper class that listens to the buttons located at the bottom
89 * @specnote Apparently this class was intended to be protected,
90 * but was made public by a compiler bug and is now
91 * public for compatibility.
93 public class ButtonActionListener
implements ActionListener
95 /** The index of the option this button represents. */
96 protected int buttonIndex
;
99 * Creates a new ButtonActionListener object with the given buttonIndex.
101 * @param buttonIndex The index of the option this button represents.
103 public ButtonActionListener(int buttonIndex
)
105 this.buttonIndex
= buttonIndex
;
109 * This method is called when one of the option buttons are pressed.
111 * @param e The ActionEvent.
113 public void actionPerformed(ActionEvent e
)
115 Object value
= new Integer(JOptionPane
.CLOSED_OPTION
);
116 Object
[] options
= optionPane
.getOptions();
118 value
= new Integer(buttonIndex
);
121 String text
= ((JButton
) e
.getSource()).getText();
122 if (text
.equals(OK_STRING
))
123 value
= new Integer(JOptionPane
.OK_OPTION
);
124 if (text
.equals(CANCEL_STRING
))
125 value
= new Integer(JOptionPane
.CANCEL_OPTION
);
126 if (text
.equals(YES_STRING
))
127 value
= new Integer(JOptionPane
.YES_OPTION
);
128 if (text
.equals(NO_STRING
))
129 value
= new Integer(JOptionPane
.NO_OPTION
);
131 optionPane
.setValue(value
);
134 Window owner
= SwingUtilities
.windowForComponent(optionPane
);
136 if (owner
instanceof JDialog
)
137 ((JDialog
) owner
).dispose();
139 //else we probably have some kind of internal frame.
140 JInternalFrame inf
= (JInternalFrame
) SwingUtilities
.getAncestorOfClass(JInternalFrame
.class,
148 catch (PropertyVetoException pve
)
150 // We do nothing if attempt has been vetoed.
157 * This helper layout manager is responsible for the layout of the button
158 * area. The button area is the panel that holds the buttons which
159 * represent the options.
161 * @specnote Apparently this class was intended to be protected,
162 * but was made public by a compiler bug and is now
163 * public for compatibility.
165 public static class ButtonAreaLayout
implements LayoutManager
167 /** Whether this layout will center the buttons. */
168 protected boolean centersChildren
= true;
170 /** The space between the buttons. */
171 protected int padding
;
173 /** Whether the buttons will share the same widths. */
174 protected boolean syncAllWidths
;
176 /** The width of the widest button. */
177 private transient int widthOfWidestButton
;
179 /** The height of the tallest button. */
180 private transient int tallestButton
;
183 * Creates a new ButtonAreaLayout object with the given sync widths
184 * property and padding.
186 * @param syncAllWidths Whether the buttons will share the same widths.
187 * @param padding The padding between the buttons.
189 public ButtonAreaLayout(boolean syncAllWidths
, int padding
)
191 this.syncAllWidths
= syncAllWidths
;
192 this.padding
= padding
;
196 * This method is called when a component is added to the container.
198 * @param string The constraints string.
199 * @param comp The component added.
201 public void addLayoutComponent(String string
, Component comp
)
207 * This method returns whether the children will be centered.
209 * @return Whether the children will be centered.
211 public boolean getCentersChildren()
213 return centersChildren
;
217 * This method returns the amount of space between components.
219 * @return The amount of space between components.
221 public int getPadding()
227 * This method returns whether all components will share widths (set to
230 * @return Whether all components will share widths.
232 public boolean getSyncAllWidths()
234 return syncAllWidths
;
238 * This method lays out the given container.
240 * @param container The container to lay out.
242 public void layoutContainer(Container container
)
244 Component
[] buttonList
= container
.getComponents();
245 int x
= container
.getInsets().left
;
246 if (getCentersChildren())
247 x
+= (int) ((double) (container
.getSize().width
) / 2
248 - (double) (buttonRowLength(container
)) / 2);
249 for (int i
= 0; i
< buttonList
.length
; i
++)
251 Dimension dims
= buttonList
[i
].getPreferredSize();
254 buttonList
[i
].setBounds(x
, 0, widthOfWidestButton
, dims
.height
);
255 x
+= widthOfWidestButton
+ getPadding();
259 buttonList
[i
].setBounds(x
, 0, dims
.width
, dims
.height
);
260 x
+= dims
.width
+ getPadding();
266 * This method returns the width of the given container taking into
267 * consideration the padding and syncAllWidths.
269 * @param c The container to calculate width for.
271 * @return The width of the given container.
273 private int buttonRowLength(Container c
)
275 Component
[] buttonList
= c
.getComponents();
277 int buttonLength
= 0;
281 for (int i
= 0; i
< buttonList
.length
; i
++)
283 Dimension dims
= buttonList
[i
].getPreferredSize();
284 buttonLength
+= dims
.width
+ getPadding();
285 widest
= Math
.max(widest
, dims
.width
);
286 tallest
= Math
.max(tallest
, dims
.height
);
289 widthOfWidestButton
= widest
;
290 tallestButton
= tallest
;
293 if (getSyncAllWidths())
294 width
= widest
* buttonList
.length
295 + getPadding() * (buttonList
.length
- 1);
297 width
= buttonLength
;
299 Insets insets
= c
.getInsets();
300 width
+= insets
.left
+ insets
.right
;
306 * This method returns the minimum layout size for the given container.
308 * @param c The container to measure.
310 * @return The minimum layout size.
312 public Dimension
minimumLayoutSize(Container c
)
314 return preferredLayoutSize(c
);
318 * This method returns the preferred size of the given container.
320 * @param c The container to measure.
322 * @return The preferred size.
324 public Dimension
preferredLayoutSize(Container c
)
326 int w
= buttonRowLength(c
);
328 return new Dimension(w
, tallestButton
);
332 * This method removes the given component from the layout manager's
335 * @param c The component to remove.
337 public void removeLayoutComponent(Component c
)
343 * This method sets whether the children will be centered.
345 * @param newValue Whether the children will be centered.
347 public void setCentersChildren(boolean newValue
)
349 centersChildren
= newValue
;
353 * This method sets the amount of space between each component.
355 * @param newPadding The padding between components.
357 public void setPadding(int newPadding
)
359 padding
= newPadding
;
363 * This method sets whether the widths will be synced.
365 * @param newValue Whether the widths will be synced.
367 public void setSyncAllWidths(boolean newValue
)
369 syncAllWidths
= newValue
;
374 * This helper class handles property change events from the JOptionPane.
376 * @specnote Apparently this class was intended to be protected,
377 * but was made public by a compiler bug and is now
378 * public for compatibility.
380 public class PropertyChangeHandler
implements PropertyChangeListener
383 * This method is called when one of the properties of the JOptionPane
386 * @param e The PropertyChangeEvent.
388 public void propertyChange(PropertyChangeEvent e
)
390 if (e
.getPropertyName().equals(JOptionPane
.ICON_PROPERTY
)
391 || e
.getPropertyName().equals(JOptionPane
.MESSAGE_TYPE_PROPERTY
))
392 addIcon(messageAreaContainer
);
393 else if (e
.getPropertyName().equals(JOptionPane
.INITIAL_SELECTION_VALUE_PROPERTY
))
394 resetSelectedValue();
395 else if (e
.getPropertyName().equals(JOptionPane
.INITIAL_VALUE_PROPERTY
)
396 || e
.getPropertyName().equals(JOptionPane
.OPTIONS_PROPERTY
)
397 || e
.getPropertyName().equals(JOptionPane
.OPTION_TYPE_PROPERTY
))
399 Container newButtons
= createButtonArea();
400 optionPane
.remove(buttonContainer
);
401 optionPane
.add(newButtons
);
402 buttonContainer
= newButtons
;
405 else if (e
.getPropertyName().equals(JOptionPane
.MESSAGE_PROPERTY
)
406 || e
.getPropertyName().equals(JOptionPane
.WANTS_INPUT_PROPERTY
)
407 || e
.getPropertyName().equals(JOptionPane
.SELECTION_VALUES_PROPERTY
))
409 optionPane
.remove(messageAreaContainer
);
410 messageAreaContainer
= createMessageArea();
411 optionPane
.add(messageAreaContainer
);
412 Container newButtons
= createButtonArea();
413 optionPane
.remove(buttonContainer
);
414 optionPane
.add(newButtons
);
415 buttonContainer
= newButtons
;
416 optionPane
.add(buttonContainer
);
418 optionPane
.invalidate();
419 optionPane
.repaint();
424 * The minimum width for JOptionPanes.
426 public static final int MinimumWidth
= 262;
429 * The minimum height for JOptionPanes.
431 public static final int MinimumHeight
= 90;
433 /** Whether the JOptionPane contains custom components. */
434 protected boolean hasCustomComponents
= false;
436 // The initialFocusComponent seems to always be set to a button (even if
437 // I try to set initialSelectionValue). This is different from what the
438 // javadocs state (which should switch this reference to the input component
439 // if one is present since that is what's going to get focus).
442 * The button that will receive focus based on initialValue when no input
443 * component is present. If an input component is present, then the input
444 * component will receive focus instead.
446 protected Component initialFocusComponent
;
448 /** The component that receives input when the JOptionPane needs it. */
449 protected JComponent inputComponent
;
451 /** The minimum dimensions of the JOptionPane. */
452 protected Dimension minimumSize
;
454 /** The propertyChangeListener for the JOptionPane. */
455 protected PropertyChangeListener propertyChangeListener
;
457 /** The JOptionPane this UI delegate is used for. */
458 protected JOptionPane optionPane
;
460 /** The size of the icons. */
461 // FIXME: wrong name for a constant.
462 private static final int iconSize
= 36;
464 /** The foreground color for the message area. */
465 private transient Color messageForeground
;
467 /** The border around the message area. */
468 private transient Border messageBorder
;
470 /** The border around the button area. */
471 private transient Border buttonBorder
;
473 /** The string used to describe OK buttons. */
474 private static final String OK_STRING
= "OK";
476 /** The string used to describe Yes buttons. */
477 private static final String YES_STRING
= "Yes";
479 /** The string used to describe No buttons. */
480 private static final String NO_STRING
= "No";
482 /** The string used to describe Cancel buttons. */
483 private static final String CANCEL_STRING
= "Cancel";
485 /** The container for the message area.
486 * This is package-private to avoid an accessor method. */
487 transient Container messageAreaContainer
;
489 /** The container for the buttons.
490 * This is package-private to avoid an accessor method. */
491 transient Container buttonContainer
;
494 * A helper class that implements Icon. This is used temporarily until
495 * ImageIcons are fixed.
497 private static class MessageIcon
implements Icon
500 * This method returns the width of the icon.
502 * @return The width of the icon.
504 public int getIconWidth()
510 * This method returns the height of the icon.
512 * @return The height of the icon.
514 public int getIconHeight()
520 * This method paints the icon as a part of the given component using the
521 * given graphics and the given x and y position.
523 * @param c The component that owns this icon.
524 * @param g The Graphics object to paint with.
525 * @param x The x coordinate.
526 * @param y The y coordinate.
528 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
530 // Nothing to do here.
534 /** The icon displayed for ERROR_MESSAGE. */
535 private static MessageIcon errorIcon
= new MessageIcon()
537 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
539 Polygon oct
= new Polygon(new int[] { 0, 0, 9, 27, 36, 36, 27, 9 },
540 new int[] { 9, 27, 36, 36, 27, 9, 0, 0 }, 8);
543 Color saved
= g
.getColor();
544 g
.setColor(Color
.RED
);
548 g
.setColor(Color
.BLACK
);
549 g
.drawRect(13, 16, 10, 4);
556 /** The icon displayed for INFORMATION_MESSAGE. */
557 private static MessageIcon infoIcon
= new MessageIcon()
559 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
562 Color saved
= g
.getColor();
565 g
.setColor(Color
.RED
);
567 g
.fillOval(0, 0, iconSize
, iconSize
);
569 g
.setColor(Color
.BLACK
);
570 g
.drawOval(16, 6, 4, 4);
572 Polygon bottomI
= new Polygon(new int[] { 15, 15, 13, 13, 23, 23, 21, 21 },
573 new int[] { 12, 28, 28, 30, 30, 28, 28, 12 },
575 g
.drawPolygon(bottomI
);
582 /** The icon displayed for WARNING_MESSAGE. */
583 private static MessageIcon warningIcon
= new MessageIcon()
585 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
588 Color saved
= g
.getColor();
589 g
.setColor(Color
.YELLOW
);
591 Polygon triangle
= new Polygon(new int[] { 0, 18, 36 },
592 new int[] { 36, 0, 36 }, 3);
593 g
.fillPolygon(triangle
);
595 g
.setColor(Color
.BLACK
);
597 Polygon excl
= new Polygon(new int[] { 15, 16, 20, 21 },
598 new int[] { 8, 26, 26, 8 }, 4);
600 g
.drawOval(16, 30, 4, 4);
607 /** The icon displayed for MESSAGE_ICON. */
608 private static MessageIcon questionIcon
= new MessageIcon()
610 public void paintIcon(Component c
, Graphics g
, int x
, int y
)
613 Color saved
= g
.getColor();
614 g
.setColor(Color
.GREEN
);
616 g
.fillRect(0, 0, iconSize
, iconSize
);
618 g
.setColor(Color
.BLACK
);
620 g
.drawOval(11, 2, 16, 16);
621 g
.drawOval(14, 5, 10, 10);
623 g
.setColor(Color
.GREEN
);
624 g
.fillRect(0, 10, iconSize
, iconSize
- 10);
626 g
.setColor(Color
.BLACK
);
628 g
.drawLine(11, 10, 14, 10);
630 g
.drawLine(24, 10, 17, 22);
631 g
.drawLine(27, 10, 20, 22);
632 g
.drawLine(17, 22, 20, 22);
634 g
.drawOval(17, 25, 3, 3);
641 // FIXME: Uncomment when the ImageIcons are fixed.
643 /* IconUIResource warningIcon, questionIcon, infoIcon, errorIcon;*/
646 * Creates a new BasicOptionPaneUI object.
648 public BasicOptionPaneUI()
650 // Nothing to do here.
654 * This method is messaged to add the buttons to the given container.
656 * @param container The container to add components to.
657 * @param buttons The buttons to add. (If it is an instance of component,
658 * the Object is added directly. If it is an instance of Icon, it is
659 * packed into a label and added. For all other cases, the string
660 * representation of the Object is retreived and packed into a
662 * @param initialIndex The index of the component that is the initialValue.
664 protected void addButtonComponents(Container container
, Object
[] buttons
,
669 for (int i
= 0; i
< buttons
.length
; i
++)
671 if (buttons
[i
] != null)
674 if (buttons
[i
] instanceof Component
)
675 toAdd
= (Component
) buttons
[i
];
678 if (buttons
[i
] instanceof Icon
)
679 toAdd
= new JButton((Icon
) buttons
[i
]);
681 toAdd
= new JButton(buttons
[i
].toString());
682 hasCustomComponents
= true;
684 if (toAdd
instanceof JButton
)
685 ((JButton
) toAdd
).addActionListener(createButtonActionListener(i
));
686 if (i
== initialIndex
)
687 initialFocusComponent
= toAdd
;
688 container
.add(toAdd
);
691 selectInitialValue(optionPane
);
695 * This method adds the appropriate icon the given container.
697 * @param top The container to add an icon to.
699 protected void addIcon(Container top
)
701 JLabel iconLabel
= null;
702 Icon icon
= getIcon();
705 iconLabel
= new JLabel(icon
);
706 top
.add(iconLabel
, BorderLayout
.WEST
);
711 * A helper method that returns an instance of GridBagConstraints to be used
712 * for creating the message area.
714 * @return An instance of GridBagConstraints.
716 private static GridBagConstraints
createConstraints()
718 GridBagConstraints constraints
= new GridBagConstraints();
719 constraints
.gridx
= GridBagConstraints
.REMAINDER
;
720 constraints
.gridy
= GridBagConstraints
.REMAINDER
;
721 constraints
.gridwidth
= 0;
722 constraints
.anchor
= GridBagConstraints
.LINE_START
;
723 constraints
.fill
= GridBagConstraints
.NONE
;
724 constraints
.insets
= new Insets(0, 0, 3, 0);
730 * This method creates the proper object (if necessary) to represent msg.
731 * (If msg is an instance of Component, it will add it directly. If it is
732 * an icon, then it will pack it in a label and add it. Otherwise, it gets
733 * treated as a string. If the string is longer than maxll, a box is
734 * created and the burstStringInto is called with the box as the container.
735 * The box is then added to the given container. Otherwise, the string is
736 * packed in a label and placed in the given container.) This method is
737 * also used for adding the inputComponent to the container.
739 * @param container The container to add to.
740 * @param cons The constraints when adding.
741 * @param msg The message to add.
742 * @param maxll The max line length.
743 * @param internallyCreated Whether the msg is internally created.
745 protected void addMessageComponents(Container container
,
746 GridBagConstraints cons
, Object msg
,
747 int maxll
, boolean internallyCreated
)
751 hasCustomComponents
= internallyCreated
;
752 if (msg
instanceof Object
[])
754 Object
[] arr
= (Object
[]) msg
;
755 for (int i
= 0; i
< arr
.length
; i
++)
756 addMessageComponents(container
, cons
, arr
[i
], maxll
,
760 else if (msg
instanceof Component
)
762 container
.add((Component
) msg
, cons
);
765 else if (msg
instanceof Icon
)
767 container
.add(new JLabel((Icon
) msg
), cons
);
772 // Undocumented behaviour.
773 // if msg.toString().length greater than maxll
774 // it will create a box and burst the string.
775 // otherwise, it will just create a label and re-call
776 // this method with the label o.O
777 if (msg
.toString().length() > maxll
|| msg
.toString().contains("\n"))
779 Box tmp
= new Box(BoxLayout
.Y_AXIS
);
780 burstStringInto(tmp
, msg
.toString(), maxll
);
781 addMessageComponents(container
, cons
, tmp
, maxll
, true);
784 addMessageComponents(container
, cons
, new JLabel(msg
.toString()),
790 * This method creates instances of d (recursively if necessary based on
791 * maxll) and adds to c.
793 * @param c The container to add to.
794 * @param d The string to burst.
795 * @param maxll The max line length.
797 protected void burstStringInto(Container c
, String d
, int maxll
)
799 if (d
== null || c
== null)
802 int newlineIndex
= d
.indexOf('\n');
805 if (newlineIndex
>= 0 && newlineIndex
< maxll
)
807 line
= d
.substring(0, newlineIndex
);
808 remainder
= d
.substring(newlineIndex
+ 1);
812 line
= d
.substring(0, maxll
);
813 remainder
= d
.substring(maxll
);
815 JLabel label
= new JLabel(line
);
818 // If there is nothing left to burst, then we can stop.
819 if (remainder
.length() == 0)
822 // Recursivly call ourselves to burst the remainder of the string,
823 if ((remainder
.length() > maxll
|| remainder
.contains("\n")))
824 burstStringInto(c
, remainder
, maxll
);
826 // Add the remainder to the container and be done.
827 c
.add(new JLabel(remainder
));
831 * This method returns true if the given JOptionPane contains custom
834 * @param op The JOptionPane to check.
836 * @return True if the JOptionPane contains custom components.
838 public boolean containsCustomComponents(JOptionPane op
)
840 return hasCustomComponents
;
844 * This method creates a button action listener for the given button index.
846 * @param buttonIndex The index of the button in components.
848 * @return A new ButtonActionListener.
850 protected ActionListener
createButtonActionListener(int buttonIndex
)
852 return new ButtonActionListener(buttonIndex
);
856 * This method creates the button area.
858 * @return A new Button Area.
860 protected Container
createButtonArea()
862 JPanel buttonPanel
= new JPanel();
864 buttonPanel
.setLayout(createLayoutManager());
865 addButtonComponents(buttonPanel
, getButtons(), getInitialValueIndex());
871 * This method creates a new LayoutManager for the button area.
873 * @return A new LayoutManager for the button area.
875 protected LayoutManager
createLayoutManager()
877 return new ButtonAreaLayout(getSizeButtonsToSameWidth(), 6);
881 * This method creates the message area.
883 * @return A new message area.
885 protected Container
createMessageArea()
887 JPanel messageArea
= new JPanel();
888 messageArea
.setLayout(new BorderLayout());
889 addIcon(messageArea
);
891 JPanel rightSide
= new JPanel();
892 rightSide
.setBorder(BorderFactory
.createEmptyBorder(10, 10, 10, 10));
893 rightSide
.setLayout(new GridBagLayout());
894 GridBagConstraints con
= createConstraints();
896 addMessageComponents(rightSide
, con
, getMessage(),
897 getMaxCharactersPerLineCount(), false);
899 if (optionPane
.getWantsInput())
901 Object
[] selection
= optionPane
.getSelectionValues();
903 if (selection
== null)
904 inputComponent
= new JTextField(15);
905 else if (selection
.length
< 20)
906 inputComponent
= new JComboBox(selection
);
908 inputComponent
= new JList(selection
);
909 if (inputComponent
!= null)
911 addMessageComponents(rightSide
, con
, inputComponent
,
912 getMaxCharactersPerLineCount(), false);
913 resetSelectedValue();
914 selectInitialValue(optionPane
);
918 messageArea
.add(rightSide
, BorderLayout
.CENTER
);
924 * This method creates a new PropertyChangeListener for listening to the
927 * @return A new PropertyChangeListener.
929 protected PropertyChangeListener
createPropertyChangeListener()
931 return new PropertyChangeHandler();
935 * This method creates a Container that will separate the message and button
938 * @return A Container that will separate the message and button areas.
940 protected Container
createSeparator()
942 // FIXME: Figure out what this method is supposed to return and where
943 // this should be added to the OptionPane.
948 * This method creates a new BasicOptionPaneUI for the given component.
950 * @param x The component to create a UI for.
952 * @return A new BasicOptionPaneUI.
954 public static ComponentUI
createUI(JComponent x
)
956 return new BasicOptionPaneUI();
960 * This method returns the buttons for the JOptionPane. If no options are
961 * set, a set of options will be created based upon the optionType.
963 * @return The buttons that will be added.
965 protected Object
[] getButtons()
967 if (optionPane
.getOptions() != null)
968 return optionPane
.getOptions();
969 switch (optionPane
.getOptionType())
971 case JOptionPane
.YES_NO_OPTION
:
972 return new Object
[] { YES_STRING
, NO_STRING
};
973 case JOptionPane
.YES_NO_CANCEL_OPTION
:
974 return new Object
[] { YES_STRING
, NO_STRING
, CANCEL_STRING
};
975 case JOptionPane
.OK_CANCEL_OPTION
:
976 return new Object
[] { OK_STRING
, CANCEL_STRING
};
977 case JOptionPane
.DEFAULT_OPTION
:
978 return (optionPane
.getWantsInput() ) ?
979 new Object
[] { OK_STRING
, CANCEL_STRING
} :
980 ( optionPane
.getMessageType() == JOptionPane
.QUESTION_MESSAGE
) ?
981 new Object
[] { YES_STRING
, NO_STRING
, CANCEL_STRING
} :
982 // ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE
983 new Object
[] { OK_STRING
};
989 * This method will return the icon the user has set or the icon that will
990 * be used based on message type.
992 * @return The icon to use in the JOptionPane.
994 protected Icon
getIcon()
996 if (optionPane
.getIcon() != null)
997 return optionPane
.getIcon();
999 return getIconForType(optionPane
.getMessageType());
1003 * This method returns the icon for the given messageType.
1005 * @param messageType The type of message.
1007 * @return The icon for the given messageType.
1009 protected Icon
getIconForType(int messageType
)
1012 switch (messageType
)
1014 case JOptionPane
.ERROR_MESSAGE
:
1017 case JOptionPane
.INFORMATION_MESSAGE
:
1020 case JOptionPane
.WARNING_MESSAGE
:
1023 case JOptionPane
.QUESTION_MESSAGE
:
1028 // FIXME: Don't cast till the default icons are in.
1029 // return new IconUIResource(tmp);
1033 * This method returns the index of the initialValue in the options array.
1035 * @return The index of the initalValue.
1037 protected int getInitialValueIndex()
1039 Object
[] buttons
= getButtons();
1041 if (buttons
== null)
1044 Object select
= optionPane
.getInitialValue();
1046 for (int i
= 0; i
< buttons
.length
; i
++)
1048 if (select
== buttons
[i
])
1055 * This method returns the maximum number of characters that should be
1058 * @return The maximum number of characteres that should be placed on a
1061 protected int getMaxCharactersPerLineCount()
1063 return optionPane
.getMaxCharactersPerLineCount();
1067 * This method returns the maximum size.
1069 * @param c The JComponent to measure.
1071 * @return The maximum size.
1073 public Dimension
getMaximumSize(JComponent c
)
1075 return getPreferredSize(c
);
1079 * This method returns the message of the JOptionPane.
1081 * @return The message.
1083 protected Object
getMessage()
1085 return optionPane
.getMessage();
1089 * This method returns the minimum size of the JOptionPane.
1091 * @return The minimum size.
1093 public Dimension
getMinimumOptionPaneSize()
1099 * This method returns the minimum size.
1101 * @param c The JComponent to measure.
1103 * @return The minimum size.
1105 public Dimension
getMinimumSize(JComponent c
)
1107 return getPreferredSize(c
);
1111 * This method returns the preferred size of the JOptionPane. The preferred
1112 * size is the maximum of the size desired by the layout and the minimum
1115 * @param c The JComponent to measure.
1117 * @return The preferred size.
1119 public Dimension
getPreferredSize(JComponent c
)
1121 Dimension d
= optionPane
.getLayout().preferredLayoutSize(optionPane
);
1122 Dimension d2
= getMinimumOptionPaneSize();
1124 int w
= Math
.max(d
.width
, d2
.width
);
1125 int h
= Math
.max(d
.height
, d2
.height
);
1126 return new Dimension(w
, h
);
1130 * This method returns whether all buttons should have the same width.
1132 * @return Whether all buttons should have the same width.
1134 protected boolean getSizeButtonsToSameWidth()
1140 * This method installs components for the JOptionPane.
1142 protected void installComponents()
1145 hasCustomComponents
= false;
1146 Container msg
= createMessageArea();
1149 ((JComponent
) msg
).setBorder(messageBorder
);
1150 msg
.setForeground(messageForeground
);
1151 messageAreaContainer
= msg
;
1152 optionPane
.add(msg
);
1155 // FIXME: Figure out if the separator should be inserted here or what
1156 // this thing is supposed to do. Note: The JDK does NOT insert another
1157 // component at this place. The JOptionPane only has two panels in it
1158 // and there actually are applications that depend on this beeing so.
1159 Container sep
= createSeparator();
1161 optionPane
.add(sep
);
1163 Container button
= createButtonArea();
1166 ((JComponent
) button
).setBorder(buttonBorder
);
1167 buttonContainer
= button
;
1168 optionPane
.add(button
);
1171 optionPane
.setBorder(BorderFactory
.createEmptyBorder(12, 12, 11, 11));
1172 optionPane
.invalidate();
1176 * This method installs defaults for the JOptionPane.
1178 protected void installDefaults()
1180 LookAndFeel
.installColorsAndFont(optionPane
, "OptionPane.background",
1181 "OptionPane.foreground",
1183 LookAndFeel
.installBorder(optionPane
, "OptionPane.border");
1184 optionPane
.setOpaque(true);
1186 messageBorder
= UIManager
.getBorder("OptionPane.messageAreaBorder");
1187 messageForeground
= UIManager
.getColor("OptionPane.messageForeground");
1188 buttonBorder
= UIManager
.getBorder("OptionPane.buttonAreaBorder");
1190 minimumSize
= UIManager
.getDimension("OptionPane.minimumSize");
1192 // FIXME: Image icons don't seem to work properly right now.
1193 // Once they do, replace the synthetic icons with these ones.
1196 warningIcon = (IconUIResource) defaults.getIcon("OptionPane.warningIcon");
1197 infoIcon = (IconUIResource) defaults.getIcon("OptionPane.informationIcon");
1198 errorIcon = (IconUIResource) defaults.getIcon("OptionPane.errorIcon");
1199 questionIcon = (IconUIResource) defaults.getIcon("OptionPane.questionIcon");
1204 * This method installs keyboard actions for the JOptionpane.
1206 protected void installKeyboardActions()
1208 // FIXME: implement.
1212 * This method installs listeners for the JOptionPane.
1214 protected void installListeners()
1216 propertyChangeListener
= createPropertyChangeListener();
1218 optionPane
.addPropertyChangeListener(propertyChangeListener
);
1222 * This method installs the UI for the JOptionPane.
1224 * @param c The JComponent to install the UI for.
1226 public void installUI(JComponent c
)
1228 if (c
instanceof JOptionPane
)
1230 optionPane
= (JOptionPane
) c
;
1233 installComponents();
1235 installKeyboardActions();
1240 * Changes the inputValue property in the JOptionPane based on the current
1241 * value of the inputComponent.
1243 protected void resetInputValue()
1245 if (optionPane
.getWantsInput() && inputComponent
!= null)
1247 Object output
= null;
1248 if (inputComponent
instanceof JTextField
)
1249 output
= ((JTextField
) inputComponent
).getText();
1250 else if (inputComponent
instanceof JComboBox
)
1251 output
= ((JComboBox
) inputComponent
).getSelectedItem();
1252 else if (inputComponent
instanceof JList
)
1253 output
= ((JList
) inputComponent
).getSelectedValue();
1256 optionPane
.setInputValue(output
);
1261 * This method requests focus to the inputComponent (if one is present) and
1262 * the initialFocusComponent otherwise.
1264 * @param op The JOptionPane.
1266 public void selectInitialValue(JOptionPane op
)
1268 if (inputComponent
!= null)
1270 inputComponent
.requestFocus();
1273 if (initialFocusComponent
!= null)
1274 initialFocusComponent
.requestFocus();
1278 * This method resets the value in the inputComponent to the
1279 * initialSelectionValue property.
1280 * This is package-private to avoid an accessor method.
1282 void resetSelectedValue()
1284 if (inputComponent
!= null)
1286 Object init
= optionPane
.getInitialSelectionValue();
1289 if (inputComponent
instanceof JTextField
)
1290 ((JTextField
) inputComponent
).setText((String
) init
);
1291 else if (inputComponent
instanceof JComboBox
)
1292 ((JComboBox
) inputComponent
).setSelectedItem(init
);
1293 else if (inputComponent
instanceof JList
)
1295 // ((JList) inputComponent).setSelectedValue(init, true);
1301 * This method uninstalls all the components in the JOptionPane.
1303 protected void uninstallComponents()
1305 optionPane
.removeAll();
1306 buttonContainer
= null;
1307 messageAreaContainer
= null;
1311 * This method uninstalls the defaults for the JOptionPane.
1313 protected void uninstallDefaults()
1315 optionPane
.setFont(null);
1316 optionPane
.setForeground(null);
1317 optionPane
.setBackground(null);
1321 messageBorder
= null;
1322 buttonBorder
= null;
1323 messageForeground
= null;
1325 // FIXME: ImageIcons don't seem to work properly
1330 questionIcon = null;
1336 * This method uninstalls keyboard actions for the JOptionPane.
1338 protected void uninstallKeyboardActions()
1340 // FIXME: implement.
1344 * This method uninstalls listeners for the JOptionPane.
1346 protected void uninstallListeners()
1348 optionPane
.removePropertyChangeListener(propertyChangeListener
);
1349 propertyChangeListener
= null;
1353 * This method uninstalls the UI for the given JComponent.
1355 * @param c The JComponent to uninstall for.
1357 public void uninstallUI(JComponent c
)
1359 uninstallKeyboardActions();
1360 uninstallListeners();
1361 uninstallComponents();
1362 uninstallDefaults();