Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / plaf / basic / BasicOptionPaneUI.java
blob88bca3b53ce867cead7a3f7134e4042cb7f90839
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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 gnu.classpath.NotImplementedException;
43 import java.awt.BorderLayout;
44 import java.awt.Color;
45 import java.awt.Component;
46 import java.awt.Container;
47 import java.awt.Dimension;
48 import java.awt.Graphics;
49 import java.awt.GridBagConstraints;
50 import java.awt.GridBagLayout;
51 import java.awt.Insets;
52 import java.awt.LayoutManager;
53 import java.awt.Polygon;
54 import java.awt.Window;
55 import java.awt.event.ActionEvent;
56 import java.awt.event.ActionListener;
57 import java.beans.PropertyChangeEvent;
58 import java.beans.PropertyChangeListener;
59 import java.beans.PropertyVetoException;
61 import javax.swing.BorderFactory;
62 import javax.swing.Box;
63 import javax.swing.BoxLayout;
64 import javax.swing.Icon;
65 import javax.swing.JButton;
66 import javax.swing.JComboBox;
67 import javax.swing.JComponent;
68 import javax.swing.JDialog;
69 import javax.swing.JInternalFrame;
70 import javax.swing.JLabel;
71 import javax.swing.JList;
72 import javax.swing.JOptionPane;
73 import javax.swing.JPanel;
74 import javax.swing.JTextField;
75 import javax.swing.LookAndFeel;
76 import javax.swing.SwingUtilities;
77 import javax.swing.UIManager;
78 import javax.swing.border.Border;
79 import javax.swing.plaf.ComponentUI;
80 import javax.swing.plaf.OptionPaneUI;
82 /**
83 * This class is the UI delegate for JOptionPane in the Basic Look and Feel.
85 public class BasicOptionPaneUI extends OptionPaneUI
87 /**
88 * This is a helper class that listens to the buttons located at the bottom
89 * of the JOptionPane.
91 * @specnote Apparently this class was intended to be protected,
92 * but was made public by a compiler bug and is now
93 * public for compatibility.
95 public class ButtonActionListener implements ActionListener
97 /** The index of the option this button represents. */
98 protected int buttonIndex;
101 * Creates a new ButtonActionListener object with the given buttonIndex.
103 * @param buttonIndex The index of the option this button represents.
105 public ButtonActionListener(int buttonIndex)
107 this.buttonIndex = buttonIndex;
111 * This method is called when one of the option buttons are pressed.
113 * @param e The ActionEvent.
115 public void actionPerformed(ActionEvent e)
117 Object value = new Integer(JOptionPane.CLOSED_OPTION);
118 Object[] options = optionPane.getOptions();
119 if (options != null)
120 value = new Integer(buttonIndex);
121 else
123 String text = ((JButton) e.getSource()).getText();
124 if (text.equals(OK_STRING))
125 value = new Integer(JOptionPane.OK_OPTION);
126 if (text.equals(CANCEL_STRING))
127 value = new Integer(JOptionPane.CANCEL_OPTION);
128 if (text.equals(YES_STRING))
129 value = new Integer(JOptionPane.YES_OPTION);
130 if (text.equals(NO_STRING))
131 value = new Integer(JOptionPane.NO_OPTION);
133 optionPane.setValue(value);
134 resetInputValue();
136 Window owner = SwingUtilities.windowForComponent(optionPane);
138 if (owner instanceof JDialog)
139 ((JDialog) owner).dispose();
141 //else we probably have some kind of internal frame.
142 JInternalFrame inf = (JInternalFrame) SwingUtilities.getAncestorOfClass(JInternalFrame.class,
143 optionPane);
144 if (inf != null)
148 inf.setClosed(true);
150 catch (PropertyVetoException pve)
152 // We do nothing if attempt has been vetoed.
159 * This helper layout manager is responsible for the layout of the button
160 * area. The button area is the panel that holds the buttons which
161 * represent the options.
163 * @specnote Apparently this class was intended to be protected,
164 * but was made public by a compiler bug and is now
165 * public for compatibility.
167 public static class ButtonAreaLayout implements LayoutManager
169 /** Whether this layout will center the buttons. */
170 protected boolean centersChildren = true;
172 /** The space between the buttons. */
173 protected int padding;
175 /** Whether the buttons will share the same widths. */
176 protected boolean syncAllWidths;
178 /** The width of the widest button. */
179 private transient int widthOfWidestButton;
181 /** The height of the tallest button. */
182 private transient int tallestButton;
185 * Creates a new ButtonAreaLayout object with the given sync widths
186 * property and padding.
188 * @param syncAllWidths Whether the buttons will share the same widths.
189 * @param padding The padding between the buttons.
191 public ButtonAreaLayout(boolean syncAllWidths, int padding)
193 this.syncAllWidths = syncAllWidths;
194 this.padding = padding;
198 * This method is called when a component is added to the container.
200 * @param string The constraints string.
201 * @param comp The component added.
203 public void addLayoutComponent(String string, Component comp)
205 // Do nothing.
209 * This method returns whether the children will be centered.
211 * @return Whether the children will be centered.
213 public boolean getCentersChildren()
215 return centersChildren;
219 * This method returns the amount of space between components.
221 * @return The amount of space between components.
223 public int getPadding()
225 return padding;
229 * This method returns whether all components will share widths (set to
230 * largest width).
232 * @return Whether all components will share widths.
234 public boolean getSyncAllWidths()
236 return syncAllWidths;
240 * This method lays out the given container.
242 * @param container The container to lay out.
244 public void layoutContainer(Container container)
246 Component[] buttonList = container.getComponents();
247 int x = container.getInsets().left;
248 if (getCentersChildren())
249 x += (int) ((double) (container.getSize().width) / 2
250 - (double) (buttonRowLength(container)) / 2);
251 for (int i = 0; i < buttonList.length; i++)
253 Dimension dims = buttonList[i].getPreferredSize();
254 if (syncAllWidths)
256 buttonList[i].setBounds(x, 0, widthOfWidestButton, dims.height);
257 x += widthOfWidestButton + getPadding();
259 else
261 buttonList[i].setBounds(x, 0, dims.width, dims.height);
262 x += dims.width + getPadding();
268 * This method returns the width of the given container taking into
269 * consideration the padding and syncAllWidths.
271 * @param c The container to calculate width for.
273 * @return The width of the given container.
275 private int buttonRowLength(Container c)
277 Component[] buttonList = c.getComponents();
279 int buttonLength = 0;
280 int widest = 0;
281 int tallest = 0;
283 for (int i = 0; i < buttonList.length; i++)
285 Dimension dims = buttonList[i].getPreferredSize();
286 buttonLength += dims.width + getPadding();
287 widest = Math.max(widest, dims.width);
288 tallest = Math.max(tallest, dims.height);
291 widthOfWidestButton = widest;
292 tallestButton = tallest;
294 int width;
295 if (getSyncAllWidths())
296 width = widest * buttonList.length
297 + getPadding() * (buttonList.length - 1);
298 else
299 width = buttonLength;
301 Insets insets = c.getInsets();
302 width += insets.left + insets.right;
304 return width;
308 * This method returns the minimum layout size for the given container.
310 * @param c The container to measure.
312 * @return The minimum layout size.
314 public Dimension minimumLayoutSize(Container c)
316 return preferredLayoutSize(c);
320 * This method returns the preferred size of the given container.
322 * @param c The container to measure.
324 * @return The preferred size.
326 public Dimension preferredLayoutSize(Container c)
328 int w = buttonRowLength(c);
330 return new Dimension(w, tallestButton);
334 * This method removes the given component from the layout manager's
335 * knowledge.
337 * @param c The component to remove.
339 public void removeLayoutComponent(Component c)
341 // Do nothing.
345 * This method sets whether the children will be centered.
347 * @param newValue Whether the children will be centered.
349 public void setCentersChildren(boolean newValue)
351 centersChildren = newValue;
355 * This method sets the amount of space between each component.
357 * @param newPadding The padding between components.
359 public void setPadding(int newPadding)
361 padding = newPadding;
365 * This method sets whether the widths will be synced.
367 * @param newValue Whether the widths will be synced.
369 public void setSyncAllWidths(boolean newValue)
371 syncAllWidths = newValue;
376 * This helper class handles property change events from the JOptionPane.
378 * @specnote Apparently this class was intended to be protected,
379 * but was made public by a compiler bug and is now
380 * public for compatibility.
382 public class PropertyChangeHandler implements PropertyChangeListener
385 * This method is called when one of the properties of the JOptionPane
386 * changes.
388 * @param e The PropertyChangeEvent.
390 public void propertyChange(PropertyChangeEvent e)
392 if (e.getPropertyName().equals(JOptionPane.ICON_PROPERTY)
393 || e.getPropertyName().equals(JOptionPane.MESSAGE_TYPE_PROPERTY))
394 addIcon(messageAreaContainer);
395 else if (e.getPropertyName().equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY))
396 resetSelectedValue();
397 else if (e.getPropertyName().equals(JOptionPane.INITIAL_VALUE_PROPERTY)
398 || e.getPropertyName().equals(JOptionPane.OPTIONS_PROPERTY)
399 || e.getPropertyName().equals(JOptionPane.OPTION_TYPE_PROPERTY))
401 Container newButtons = createButtonArea();
402 optionPane.remove(buttonContainer);
403 optionPane.add(newButtons);
404 buttonContainer = newButtons;
407 else if (e.getPropertyName().equals(JOptionPane.MESSAGE_PROPERTY)
408 || e.getPropertyName().equals(JOptionPane.WANTS_INPUT_PROPERTY)
409 || e.getPropertyName().equals(JOptionPane.SELECTION_VALUES_PROPERTY))
411 optionPane.remove(messageAreaContainer);
412 messageAreaContainer = createMessageArea();
413 optionPane.add(messageAreaContainer);
414 Container newButtons = createButtonArea();
415 optionPane.remove(buttonContainer);
416 optionPane.add(newButtons);
417 buttonContainer = newButtons;
418 optionPane.add(buttonContainer);
420 optionPane.invalidate();
421 optionPane.repaint();
426 * The minimum width for JOptionPanes.
428 public static final int MinimumWidth = 262;
431 * The minimum height for JOptionPanes.
433 public static final int MinimumHeight = 90;
435 /** Whether the JOptionPane contains custom components. */
436 protected boolean hasCustomComponents = false;
438 // The initialFocusComponent seems to always be set to a button (even if
439 // I try to set initialSelectionValue). This is different from what the
440 // javadocs state (which should switch this reference to the input component
441 // if one is present since that is what's going to get focus).
444 * The button that will receive focus based on initialValue when no input
445 * component is present. If an input component is present, then the input
446 * component will receive focus instead.
448 protected Component initialFocusComponent;
450 /** The component that receives input when the JOptionPane needs it. */
451 protected JComponent inputComponent;
453 /** The minimum dimensions of the JOptionPane. */
454 protected Dimension minimumSize;
456 /** The propertyChangeListener for the JOptionPane. */
457 protected PropertyChangeListener propertyChangeListener;
459 /** The JOptionPane this UI delegate is used for. */
460 protected JOptionPane optionPane;
462 /** The size of the icons. */
463 // FIXME: wrong name for a constant.
464 private static final int iconSize = 36;
466 /** The foreground color for the message area. */
467 private transient Color messageForeground;
469 /** The border around the message area. */
470 private transient Border messageBorder;
472 /** The border around the button area. */
473 private transient Border buttonBorder;
475 /** The string used to describe OK buttons. */
476 private static final String OK_STRING = "OK";
478 /** The string used to describe Yes buttons. */
479 private static final String YES_STRING = "Yes";
481 /** The string used to describe No buttons. */
482 private static final String NO_STRING = "No";
484 /** The string used to describe Cancel buttons. */
485 private static final String CANCEL_STRING = "Cancel";
487 /** The container for the message area.
488 * This is package-private to avoid an accessor method. */
489 transient Container messageAreaContainer;
491 /** The container for the buttons.
492 * This is package-private to avoid an accessor method. */
493 transient Container buttonContainer;
496 * A helper class that implements Icon. This is used temporarily until
497 * ImageIcons are fixed.
499 private static class MessageIcon implements Icon
502 * This method returns the width of the icon.
504 * @return The width of the icon.
506 public int getIconWidth()
508 return iconSize;
512 * This method returns the height of the icon.
514 * @return The height of the icon.
516 public int getIconHeight()
518 return iconSize;
522 * This method paints the icon as a part of the given component using the
523 * given graphics and the given x and y position.
525 * @param c The component that owns this icon.
526 * @param g The Graphics object to paint with.
527 * @param x The x coordinate.
528 * @param y The y coordinate.
530 public void paintIcon(Component c, Graphics g, int x, int y)
532 // Nothing to do here.
536 /** The icon displayed for ERROR_MESSAGE. */
537 private static MessageIcon errorIcon = new MessageIcon()
539 public void paintIcon(Component c, Graphics g, int x, int y)
541 Polygon oct = new Polygon(new int[] { 0, 0, 9, 27, 36, 36, 27, 9 },
542 new int[] { 9, 27, 36, 36, 27, 9, 0, 0 }, 8);
543 g.translate(x, y);
545 Color saved = g.getColor();
546 g.setColor(Color.RED);
548 g.fillPolygon(oct);
550 g.setColor(Color.BLACK);
551 g.drawRect(13, 16, 10, 4);
553 g.setColor(saved);
554 g.translate(-x, -y);
558 /** The icon displayed for INFORMATION_MESSAGE. */
559 private static MessageIcon infoIcon = new MessageIcon()
561 public void paintIcon(Component c, Graphics g, int x, int y)
563 g.translate(x, y);
564 Color saved = g.getColor();
566 // Should be purple.
567 g.setColor(Color.RED);
569 g.fillOval(0, 0, iconSize, iconSize);
571 g.setColor(Color.BLACK);
572 g.drawOval(16, 6, 4, 4);
574 Polygon bottomI = new Polygon(new int[] { 15, 15, 13, 13, 23, 23, 21, 21 },
575 new int[] { 12, 28, 28, 30, 30, 28, 28, 12 },
577 g.drawPolygon(bottomI);
579 g.setColor(saved);
580 g.translate(-x, -y);
584 /** The icon displayed for WARNING_MESSAGE. */
585 private static MessageIcon warningIcon = new MessageIcon()
587 public void paintIcon(Component c, Graphics g, int x, int y)
589 g.translate(x, y);
590 Color saved = g.getColor();
591 g.setColor(Color.YELLOW);
593 Polygon triangle = new Polygon(new int[] { 0, 18, 36 },
594 new int[] { 36, 0, 36 }, 3);
595 g.fillPolygon(triangle);
597 g.setColor(Color.BLACK);
599 Polygon excl = new Polygon(new int[] { 15, 16, 20, 21 },
600 new int[] { 8, 26, 26, 8 }, 4);
601 g.drawPolygon(excl);
602 g.drawOval(16, 30, 4, 4);
604 g.setColor(saved);
605 g.translate(-x, -y);
609 /** The icon displayed for MESSAGE_ICON. */
610 private static MessageIcon questionIcon = new MessageIcon()
612 public void paintIcon(Component c, Graphics g, int x, int y)
614 g.translate(x, y);
615 Color saved = g.getColor();
616 g.setColor(Color.GREEN);
618 g.fillRect(0, 0, iconSize, iconSize);
620 g.setColor(Color.BLACK);
622 g.drawOval(11, 2, 16, 16);
623 g.drawOval(14, 5, 10, 10);
625 g.setColor(Color.GREEN);
626 g.fillRect(0, 10, iconSize, iconSize - 10);
628 g.setColor(Color.BLACK);
630 g.drawLine(11, 10, 14, 10);
632 g.drawLine(24, 10, 17, 22);
633 g.drawLine(27, 10, 20, 22);
634 g.drawLine(17, 22, 20, 22);
636 g.drawOval(17, 25, 3, 3);
638 g.setColor(saved);
639 g.translate(-x, -y);
643 // FIXME: Uncomment when the ImageIcons are fixed.
645 /* IconUIResource warningIcon, questionIcon, infoIcon, errorIcon;*/
648 * Creates a new BasicOptionPaneUI object.
650 public BasicOptionPaneUI()
652 // Nothing to do here.
656 * This method is messaged to add the buttons to the given container.
658 * @param container The container to add components to.
659 * @param buttons The buttons to add. (If it is an instance of component,
660 * the Object is added directly. If it is an instance of Icon, it is
661 * packed into a label and added. For all other cases, the string
662 * representation of the Object is retreived and packed into a
663 * label.)
664 * @param initialIndex The index of the component that is the initialValue.
666 protected void addButtonComponents(Container container, Object[] buttons,
667 int initialIndex)
669 if (buttons == null)
670 return;
671 for (int i = 0; i < buttons.length; i++)
673 if (buttons[i] != null)
675 Component toAdd;
676 if (buttons[i] instanceof Component)
677 toAdd = (Component) buttons[i];
678 else
680 if (buttons[i] instanceof Icon)
681 toAdd = new JButton((Icon) buttons[i]);
682 else
683 toAdd = new JButton(buttons[i].toString());
684 hasCustomComponents = true;
686 if (toAdd instanceof JButton)
687 ((JButton) toAdd).addActionListener(createButtonActionListener(i));
688 if (i == initialIndex)
689 initialFocusComponent = toAdd;
690 container.add(toAdd);
693 selectInitialValue(optionPane);
697 * This method adds the appropriate icon the given container.
699 * @param top The container to add an icon to.
701 protected void addIcon(Container top)
703 JLabel iconLabel = null;
704 Icon icon = getIcon();
705 if (icon != null)
707 iconLabel = new JLabel(icon);
708 top.add(iconLabel, BorderLayout.WEST);
713 * A helper method that returns an instance of GridBagConstraints to be used
714 * for creating the message area.
716 * @return An instance of GridBagConstraints.
718 private static GridBagConstraints createConstraints()
720 GridBagConstraints constraints = new GridBagConstraints();
721 constraints.gridx = GridBagConstraints.REMAINDER;
722 constraints.gridy = GridBagConstraints.REMAINDER;
723 constraints.gridwidth = 0;
724 constraints.anchor = GridBagConstraints.LINE_START;
725 constraints.fill = GridBagConstraints.NONE;
726 constraints.insets = new Insets(0, 0, 3, 0);
728 return constraints;
732 * This method creates the proper object (if necessary) to represent msg.
733 * (If msg is an instance of Component, it will add it directly. If it is
734 * an icon, then it will pack it in a label and add it. Otherwise, it gets
735 * treated as a string. If the string is longer than maxll, a box is
736 * created and the burstStringInto is called with the box as the container.
737 * The box is then added to the given container. Otherwise, the string is
738 * packed in a label and placed in the given container.) This method is
739 * also used for adding the inputComponent to the container.
741 * @param container The container to add to.
742 * @param cons The constraints when adding.
743 * @param msg The message to add.
744 * @param maxll The max line length.
745 * @param internallyCreated Whether the msg is internally created.
747 protected void addMessageComponents(Container container,
748 GridBagConstraints cons, Object msg,
749 int maxll, boolean internallyCreated)
751 if (msg == null)
752 return;
753 hasCustomComponents = internallyCreated;
754 if (msg instanceof Object[])
756 Object[] arr = (Object[]) msg;
757 for (int i = 0; i < arr.length; i++)
758 addMessageComponents(container, cons, arr[i], maxll,
759 internallyCreated);
760 return;
762 else if (msg instanceof Component)
764 container.add((Component) msg, cons);
765 cons.gridy++;
767 else if (msg instanceof Icon)
769 container.add(new JLabel((Icon) msg), cons);
770 cons.gridy++;
772 else
774 // Undocumented behaviour.
775 // if msg.toString().length greater than maxll
776 // it will create a box and burst the string.
777 // otherwise, it will just create a label and re-call
778 // this method with the label o.O
779 if (msg.toString().length() > maxll || msg.toString().contains("\n"))
781 Box tmp = new Box(BoxLayout.Y_AXIS);
782 burstStringInto(tmp, msg.toString(), maxll);
783 addMessageComponents(container, cons, tmp, maxll, true);
785 else
786 addMessageComponents(container, cons, new JLabel(msg.toString()),
787 maxll, true);
792 * This method creates instances of d (recursively if necessary based on
793 * maxll) and adds to c.
795 * @param c The container to add to.
796 * @param d The string to burst.
797 * @param maxll The max line length.
799 protected void burstStringInto(Container c, String d, int maxll)
801 if (d == null || c == null)
802 return;
804 int newlineIndex = d.indexOf('\n');
805 String line;
806 String remainder;
807 if (newlineIndex >= 0 && newlineIndex < maxll)
809 line = d.substring(0, newlineIndex);
810 remainder = d.substring(newlineIndex + 1);
812 else
814 line = d.substring(0, maxll);
815 remainder = d.substring(maxll);
817 JLabel label = new JLabel(line);
818 c.add(label);
820 // If there is nothing left to burst, then we can stop.
821 if (remainder.length() == 0)
822 return;
824 // Recursivly call ourselves to burst the remainder of the string,
825 if ((remainder.length() > maxll || remainder.contains("\n")))
826 burstStringInto(c, remainder, maxll);
827 else
828 // Add the remainder to the container and be done.
829 c.add(new JLabel(remainder));
833 * This method returns true if the given JOptionPane contains custom
834 * components.
836 * @param op The JOptionPane to check.
838 * @return True if the JOptionPane contains custom components.
840 public boolean containsCustomComponents(JOptionPane op)
842 return hasCustomComponents;
846 * This method creates a button action listener for the given button index.
848 * @param buttonIndex The index of the button in components.
850 * @return A new ButtonActionListener.
852 protected ActionListener createButtonActionListener(int buttonIndex)
854 return new ButtonActionListener(buttonIndex);
858 * This method creates the button area.
860 * @return A new Button Area.
862 protected Container createButtonArea()
864 JPanel buttonPanel = new JPanel();
866 buttonPanel.setLayout(createLayoutManager());
867 addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex());
869 return buttonPanel;
873 * This method creates a new LayoutManager for the button area.
875 * @return A new LayoutManager for the button area.
877 protected LayoutManager createLayoutManager()
879 return new ButtonAreaLayout(getSizeButtonsToSameWidth(), 6);
883 * This method creates the message area.
885 * @return A new message area.
887 protected Container createMessageArea()
889 JPanel messageArea = new JPanel();
890 messageArea.setLayout(new BorderLayout());
891 addIcon(messageArea);
893 JPanel rightSide = new JPanel();
894 rightSide.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
895 rightSide.setLayout(new GridBagLayout());
896 GridBagConstraints con = createConstraints();
898 addMessageComponents(rightSide, con, getMessage(),
899 getMaxCharactersPerLineCount(), false);
901 if (optionPane.getWantsInput())
903 Object[] selection = optionPane.getSelectionValues();
905 if (selection == null)
906 inputComponent = new JTextField(15);
907 else if (selection.length < 20)
908 inputComponent = new JComboBox(selection);
909 else
910 inputComponent = new JList(selection);
911 if (inputComponent != null)
913 addMessageComponents(rightSide, con, inputComponent,
914 getMaxCharactersPerLineCount(), false);
915 resetSelectedValue();
916 selectInitialValue(optionPane);
920 messageArea.add(rightSide, BorderLayout.CENTER);
922 return messageArea;
926 * This method creates a new PropertyChangeListener for listening to the
927 * JOptionPane.
929 * @return A new PropertyChangeListener.
931 protected PropertyChangeListener createPropertyChangeListener()
933 return new PropertyChangeHandler();
937 * This method creates a Container that will separate the message and button
938 * areas.
940 * @return A Container that will separate the message and button areas.
942 protected Container createSeparator()
944 // FIXME: Figure out what this method is supposed to return and where
945 // this should be added to the OptionPane.
946 return null;
950 * This method creates a new BasicOptionPaneUI for the given component.
952 * @param x The component to create a UI for.
954 * @return A new BasicOptionPaneUI.
956 public static ComponentUI createUI(JComponent x)
958 return new BasicOptionPaneUI();
962 * This method returns the buttons for the JOptionPane. If no options are
963 * set, a set of options will be created based upon the optionType.
965 * @return The buttons that will be added.
967 protected Object[] getButtons()
969 if (optionPane.getOptions() != null)
970 return optionPane.getOptions();
971 switch (optionPane.getOptionType())
973 case JOptionPane.YES_NO_OPTION:
974 return new Object[] { YES_STRING, NO_STRING };
975 case JOptionPane.YES_NO_CANCEL_OPTION:
976 return new Object[] { YES_STRING, NO_STRING, CANCEL_STRING };
977 case JOptionPane.OK_CANCEL_OPTION:
978 return new Object[] { OK_STRING, CANCEL_STRING };
979 case JOptionPane.DEFAULT_OPTION:
980 return (optionPane.getWantsInput() ) ?
981 new Object[] { OK_STRING, CANCEL_STRING } :
982 ( optionPane.getMessageType() == JOptionPane.QUESTION_MESSAGE ) ?
983 new Object[] { YES_STRING, NO_STRING, CANCEL_STRING } :
984 // ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE
985 new Object[] { OK_STRING };
987 return null;
991 * This method will return the icon the user has set or the icon that will
992 * be used based on message type.
994 * @return The icon to use in the JOptionPane.
996 protected Icon getIcon()
998 if (optionPane.getIcon() != null)
999 return optionPane.getIcon();
1000 else
1001 return getIconForType(optionPane.getMessageType());
1005 * This method returns the icon for the given messageType.
1007 * @param messageType The type of message.
1009 * @return The icon for the given messageType.
1011 protected Icon getIconForType(int messageType)
1013 Icon tmp = null;
1014 switch (messageType)
1016 case JOptionPane.ERROR_MESSAGE:
1017 tmp = errorIcon;
1018 break;
1019 case JOptionPane.INFORMATION_MESSAGE:
1020 tmp = infoIcon;
1021 break;
1022 case JOptionPane.WARNING_MESSAGE:
1023 tmp = warningIcon;
1024 break;
1025 case JOptionPane.QUESTION_MESSAGE:
1026 tmp = questionIcon;
1027 break;
1029 return tmp;
1030 // FIXME: Don't cast till the default icons are in.
1031 // return new IconUIResource(tmp);
1035 * This method returns the index of the initialValue in the options array.
1037 * @return The index of the initalValue.
1039 protected int getInitialValueIndex()
1041 Object[] buttons = getButtons();
1043 if (buttons == null)
1044 return -1;
1046 Object select = optionPane.getInitialValue();
1048 for (int i = 0; i < buttons.length; i++)
1050 if (select == buttons[i])
1051 return i;
1053 return 0;
1057 * This method returns the maximum number of characters that should be
1058 * placed on a line.
1060 * @return The maximum number of characteres that should be placed on a
1061 * line.
1063 protected int getMaxCharactersPerLineCount()
1065 return optionPane.getMaxCharactersPerLineCount();
1069 * This method returns the maximum size.
1071 * @param c The JComponent to measure.
1073 * @return The maximum size.
1075 public Dimension getMaximumSize(JComponent c)
1077 return getPreferredSize(c);
1081 * This method returns the message of the JOptionPane.
1083 * @return The message.
1085 protected Object getMessage()
1087 return optionPane.getMessage();
1091 * This method returns the minimum size of the JOptionPane.
1093 * @return The minimum size.
1095 public Dimension getMinimumOptionPaneSize()
1097 return minimumSize;
1101 * This method returns the minimum size.
1103 * @param c The JComponent to measure.
1105 * @return The minimum size.
1107 public Dimension getMinimumSize(JComponent c)
1109 return getPreferredSize(c);
1113 * This method returns the preferred size of the JOptionPane. The preferred
1114 * size is the maximum of the size desired by the layout and the minimum
1115 * size.
1117 * @param c The JComponent to measure.
1119 * @return The preferred size.
1121 public Dimension getPreferredSize(JComponent c)
1123 Dimension d = optionPane.getLayout().preferredLayoutSize(optionPane);
1124 Dimension d2 = getMinimumOptionPaneSize();
1126 int w = Math.max(d.width, d2.width);
1127 int h = Math.max(d.height, d2.height);
1128 return new Dimension(w, h);
1132 * This method returns whether all buttons should have the same width.
1134 * @return Whether all buttons should have the same width.
1136 protected boolean getSizeButtonsToSameWidth()
1138 return true;
1142 * This method installs components for the JOptionPane.
1144 protected void installComponents()
1146 // reset it.
1147 hasCustomComponents = false;
1148 Container msg = createMessageArea();
1149 if (msg != null)
1151 ((JComponent) msg).setBorder(messageBorder);
1152 msg.setForeground(messageForeground);
1153 messageAreaContainer = msg;
1154 optionPane.add(msg);
1157 // FIXME: Figure out if the separator should be inserted here or what
1158 // this thing is supposed to do. Note: The JDK does NOT insert another
1159 // component at this place. The JOptionPane only has two panels in it
1160 // and there actually are applications that depend on this beeing so.
1161 Container sep = createSeparator();
1162 if (sep != null)
1163 optionPane.add(sep);
1165 Container button = createButtonArea();
1166 if (button != null)
1168 ((JComponent) button).setBorder(buttonBorder);
1169 buttonContainer = button;
1170 optionPane.add(button);
1173 optionPane.setBorder(BorderFactory.createEmptyBorder(12, 12, 11, 11));
1174 optionPane.invalidate();
1178 * This method installs defaults for the JOptionPane.
1180 protected void installDefaults()
1182 LookAndFeel.installColorsAndFont(optionPane, "OptionPane.background",
1183 "OptionPane.foreground",
1184 "OptionPane.font");
1185 LookAndFeel.installBorder(optionPane, "OptionPane.border");
1186 optionPane.setOpaque(true);
1188 messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
1189 messageForeground = UIManager.getColor("OptionPane.messageForeground");
1190 buttonBorder = UIManager.getBorder("OptionPane.buttonAreaBorder");
1192 minimumSize = UIManager.getDimension("OptionPane.minimumSize");
1194 // FIXME: Image icons don't seem to work properly right now.
1195 // Once they do, replace the synthetic icons with these ones.
1198 warningIcon = (IconUIResource) defaults.getIcon("OptionPane.warningIcon");
1199 infoIcon = (IconUIResource) defaults.getIcon("OptionPane.informationIcon");
1200 errorIcon = (IconUIResource) defaults.getIcon("OptionPane.errorIcon");
1201 questionIcon = (IconUIResource) defaults.getIcon("OptionPane.questionIcon");
1206 * This method installs keyboard actions for the JOptionpane.
1208 protected void installKeyboardActions()
1209 throws NotImplementedException
1211 // FIXME: implement.
1215 * This method installs listeners for the JOptionPane.
1217 protected void installListeners()
1219 propertyChangeListener = createPropertyChangeListener();
1221 optionPane.addPropertyChangeListener(propertyChangeListener);
1225 * This method installs the UI for the JOptionPane.
1227 * @param c The JComponent to install the UI for.
1229 public void installUI(JComponent c)
1231 if (c instanceof JOptionPane)
1233 optionPane = (JOptionPane) c;
1235 installDefaults();
1236 installComponents();
1237 installListeners();
1238 installKeyboardActions();
1243 * Changes the inputValue property in the JOptionPane based on the current
1244 * value of the inputComponent.
1246 protected void resetInputValue()
1248 if (optionPane.getWantsInput() && inputComponent != null)
1250 Object output = null;
1251 if (inputComponent instanceof JTextField)
1252 output = ((JTextField) inputComponent).getText();
1253 else if (inputComponent instanceof JComboBox)
1254 output = ((JComboBox) inputComponent).getSelectedItem();
1255 else if (inputComponent instanceof JList)
1256 output = ((JList) inputComponent).getSelectedValue();
1258 if (output != null)
1259 optionPane.setInputValue(output);
1264 * This method requests focus to the inputComponent (if one is present) and
1265 * the initialFocusComponent otherwise.
1267 * @param op The JOptionPane.
1269 public void selectInitialValue(JOptionPane op)
1271 if (inputComponent != null)
1273 inputComponent.requestFocus();
1274 return;
1276 if (initialFocusComponent != null)
1277 initialFocusComponent.requestFocus();
1281 * This method resets the value in the inputComponent to the
1282 * initialSelectionValue property.
1283 * This is package-private to avoid an accessor method.
1285 void resetSelectedValue()
1287 if (inputComponent != null)
1289 Object init = optionPane.getInitialSelectionValue();
1290 if (init == null)
1291 return;
1292 if (inputComponent instanceof JTextField)
1293 ((JTextField) inputComponent).setText((String) init);
1294 else if (inputComponent instanceof JComboBox)
1295 ((JComboBox) inputComponent).setSelectedItem(init);
1296 else if (inputComponent instanceof JList)
1298 // ((JList) inputComponent).setSelectedValue(init, true);
1304 * This method uninstalls all the components in the JOptionPane.
1306 protected void uninstallComponents()
1308 optionPane.removeAll();
1309 buttonContainer = null;
1310 messageAreaContainer = null;
1314 * This method uninstalls the defaults for the JOptionPane.
1316 protected void uninstallDefaults()
1318 optionPane.setFont(null);
1319 optionPane.setForeground(null);
1320 optionPane.setBackground(null);
1322 minimumSize = null;
1324 messageBorder = null;
1325 buttonBorder = null;
1326 messageForeground = null;
1328 // FIXME: ImageIcons don't seem to work properly
1331 warningIcon = null;
1332 errorIcon = null;
1333 questionIcon = null;
1334 infoIcon = null;
1339 * This method uninstalls keyboard actions for the JOptionPane.
1341 protected void uninstallKeyboardActions()
1342 throws NotImplementedException
1344 // FIXME: implement.
1348 * This method uninstalls listeners for the JOptionPane.
1350 protected void uninstallListeners()
1352 optionPane.removePropertyChangeListener(propertyChangeListener);
1353 propertyChangeListener = null;
1357 * This method uninstalls the UI for the given JComponent.
1359 * @param c The JComponent to uninstall for.
1361 public void uninstallUI(JComponent c)
1363 uninstallKeyboardActions();
1364 uninstallListeners();
1365 uninstallComponents();
1366 uninstallDefaults();
1368 optionPane = null;