0001 /*
0002 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.swing.plaf.basic;
0027
0028 import sun.swing.DefaultLookup;
0029 import sun.swing.UIAction;
0030 import javax.swing.border.Border;
0031 import javax.swing.border.EmptyBorder;
0032 import javax.swing.*;
0033 import javax.swing.event.*;
0034 import javax.swing.plaf.ActionMapUIResource;
0035 import javax.swing.plaf.ComponentUI;
0036 import javax.swing.plaf.OptionPaneUI;
0037 import java.awt.*;
0038 import java.awt.event.*;
0039 import java.beans.PropertyChangeEvent;
0040 import java.beans.PropertyChangeListener;
0041 import java.util.Locale;
0042 import java.security.AccessController;
0043
0044 import sun.security.action.GetPropertyAction;
0045
0046 /**
0047 * Provides the basic look and feel for a <code>JOptionPane</code>.
0048 * <code>BasicMessagePaneUI</code> provides a means to place an icon,
0049 * message and buttons into a <code>Container</code>.
0050 * Generally, the layout will look like:<p>
0051 * <pre>
0052 * ------------------
0053 * | i | message |
0054 * | c | message |
0055 * | o | message |
0056 * | n | message |
0057 * ------------------
0058 * | buttons |
0059 * |________________|
0060 * </pre>
0061 * icon is an instance of <code>Icon</code> that is wrapped inside a
0062 * <code>JLabel</code>. The message is an opaque object and is tested
0063 * for the following: if the message is a <code>Component</code> it is
0064 * added to the <code>Container</code>, if it is an <code>Icon</code>
0065 * it is wrapped inside a <code>JLabel</code> and added to the
0066 * <code>Container</code> otherwise it is wrapped inside a <code>JLabel</code>.
0067 * <p>
0068 * The above layout is used when the option pane's
0069 * <code>ComponentOrientation</code> property is horizontal, left-to-right.
0070 * The layout will be adjusted appropriately for other orientations.
0071 * <p>
0072 * The <code>Container</code>, message, icon, and buttons are all
0073 * determined from abstract methods.
0074 *
0075 * @version 1.67 05/05/07
0076 * @author James Gosling
0077 * @author Scott Violet
0078 * @author Amy Fowler
0079 */
0080 public class BasicOptionPaneUI extends OptionPaneUI {
0081
0082 public static final int MinimumWidth = 262;
0083 public static final int MinimumHeight = 90;
0084
0085 private static String newline;
0086
0087 /**
0088 * <code>JOptionPane</code> that the receiver is providing the
0089 * look and feel for.
0090 */
0091 protected JOptionPane optionPane;
0092
0093 protected Dimension minimumSize;
0094
0095 /** JComponent provide for input if optionPane.getWantsInput() returns
0096 * true. */
0097 protected JComponent inputComponent;
0098
0099 /** Component to receive focus when messaged with selectInitialValue. */
0100 protected Component initialFocusComponent;
0101
0102 /** This is set to true in validateComponent if a Component is contained
0103 * in either the message or the buttons. */
0104 protected boolean hasCustomComponents;
0105
0106 protected PropertyChangeListener propertyChangeListener;
0107
0108 private Handler handler;
0109
0110 static {
0111 newline = (String) java.security.AccessController
0112 .doPrivileged(new GetPropertyAction("line.separator"));
0113 if (newline == null) {
0114 newline = "\n";
0115 }
0116 }
0117
0118 static void loadActionMap(LazyActionMap map) {
0119 map.put(new Actions(Actions.CLOSE));
0120 BasicLookAndFeel.installAudioActionMap(map);
0121 }
0122
0123 /**
0124 * Creates a new BasicOptionPaneUI instance.
0125 */
0126 public static ComponentUI createUI(JComponent x) {
0127 return new BasicOptionPaneUI();
0128 }
0129
0130 /**
0131 * Installs the receiver as the L&F for the passed in
0132 * <code>JOptionPane</code>.
0133 */
0134 public void installUI(JComponent c) {
0135 optionPane = (JOptionPane) c;
0136 installDefaults();
0137 optionPane.setLayout(createLayoutManager());
0138 installComponents();
0139 installListeners();
0140 installKeyboardActions();
0141 }
0142
0143 /**
0144 * Removes the receiver from the L&F controller of the passed in split
0145 * pane.
0146 */
0147 public void uninstallUI(JComponent c) {
0148 uninstallComponents();
0149 optionPane.setLayout(null);
0150 uninstallKeyboardActions();
0151 uninstallListeners();
0152 uninstallDefaults();
0153 optionPane = null;
0154 }
0155
0156 protected void installDefaults() {
0157 LookAndFeel.installColorsAndFont(optionPane,
0158 "OptionPane.background", "OptionPane.foreground",
0159 "OptionPane.font");
0160 LookAndFeel.installBorder(optionPane, "OptionPane.border");
0161 minimumSize = UIManager.getDimension("OptionPane.minimumSize");
0162 LookAndFeel.installProperty(optionPane, "opaque", Boolean.TRUE);
0163 }
0164
0165 protected void uninstallDefaults() {
0166 LookAndFeel.uninstallBorder(optionPane);
0167 }
0168
0169 protected void installComponents() {
0170 optionPane.add(createMessageArea());
0171
0172 Container separator = createSeparator();
0173 if (separator != null) {
0174 optionPane.add(separator);
0175 }
0176 optionPane.add(createButtonArea());
0177 optionPane.applyComponentOrientation(optionPane
0178 .getComponentOrientation());
0179 }
0180
0181 protected void uninstallComponents() {
0182 hasCustomComponents = false;
0183 inputComponent = null;
0184 initialFocusComponent = null;
0185 optionPane.removeAll();
0186 }
0187
0188 protected LayoutManager createLayoutManager() {
0189 return new BoxLayout(optionPane, BoxLayout.Y_AXIS);
0190 }
0191
0192 protected void installListeners() {
0193 if ((propertyChangeListener = createPropertyChangeListener()) != null) {
0194 optionPane
0195 .addPropertyChangeListener(propertyChangeListener);
0196 }
0197 }
0198
0199 protected void uninstallListeners() {
0200 if (propertyChangeListener != null) {
0201 optionPane
0202 .removePropertyChangeListener(propertyChangeListener);
0203 propertyChangeListener = null;
0204 }
0205 handler = null;
0206 }
0207
0208 protected PropertyChangeListener createPropertyChangeListener() {
0209 return getHandler();
0210 }
0211
0212 private Handler getHandler() {
0213 if (handler == null) {
0214 handler = new Handler();
0215 }
0216 return handler;
0217 }
0218
0219 protected void installKeyboardActions() {
0220 InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
0221
0222 SwingUtilities.replaceUIInputMap(optionPane,
0223 JComponent.WHEN_IN_FOCUSED_WINDOW, map);
0224
0225 LazyActionMap.installLazyActionMap(optionPane,
0226 BasicOptionPaneUI.class, "OptionPane.actionMap");
0227 }
0228
0229 protected void uninstallKeyboardActions() {
0230 SwingUtilities.replaceUIInputMap(optionPane,
0231 JComponent.WHEN_IN_FOCUSED_WINDOW, null);
0232 SwingUtilities.replaceUIActionMap(optionPane, null);
0233 }
0234
0235 InputMap getInputMap(int condition) {
0236 if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
0237 Object[] bindings = (Object[]) DefaultLookup.get(
0238 optionPane, this , "OptionPane.windowBindings");
0239 if (bindings != null) {
0240 return LookAndFeel.makeComponentInputMap(optionPane,
0241 bindings);
0242 }
0243 }
0244 return null;
0245 }
0246
0247 /**
0248 * Returns the minimum size the option pane should be. Primarily
0249 * provided for subclassers wishing to offer a different minimum size.
0250 */
0251 public Dimension getMinimumOptionPaneSize() {
0252 if (minimumSize == null) {
0253 return new Dimension(MinimumWidth, MinimumHeight);
0254 }
0255 return new Dimension(minimumSize.width, minimumSize.height);
0256 }
0257
0258 /**
0259 * If <code>c</code> is the <code>JOptionPane</code> the receiver
0260 * is contained in, the preferred
0261 * size that is returned is the maximum of the preferred size of
0262 * the <code>LayoutManager</code> for the <code>JOptionPane</code>, and
0263 * <code>getMinimumOptionPaneSize</code>.
0264 */
0265 public Dimension getPreferredSize(JComponent c) {
0266 if ((JOptionPane) c == optionPane) {
0267 Dimension ourMin = getMinimumOptionPaneSize();
0268 LayoutManager lm = c.getLayout();
0269
0270 if (lm != null) {
0271 Dimension lmSize = lm.preferredLayoutSize(c);
0272
0273 if (ourMin != null)
0274 return new Dimension(Math.max(lmSize.width,
0275 ourMin.width), Math.max(lmSize.height,
0276 ourMin.height));
0277 return lmSize;
0278 }
0279 return ourMin;
0280 }
0281 return null;
0282 }
0283
0284 /**
0285 * Messaged from installComponents to create a Container containing the
0286 * body of the message. The icon is the created by calling
0287 * <code>addIcon</code>.
0288 */
0289 protected Container createMessageArea() {
0290 JPanel top = new JPanel();
0291 Border topBorder = (Border) DefaultLookup.get(optionPane, this ,
0292 "OptionPane.messageAreaBorder");
0293 if (topBorder != null) {
0294 top.setBorder(topBorder);
0295 }
0296 top.setLayout(new BorderLayout());
0297
0298 /* Fill the body. */
0299 Container body = new JPanel(new GridBagLayout());
0300 Container realBody = new JPanel(new BorderLayout());
0301
0302 body.setName("OptionPane.body");
0303 realBody.setName("OptionPane.realBody");
0304
0305 if (getIcon() != null) {
0306 JPanel sep = new JPanel();
0307 sep.setName("OptionPane.separator");
0308 sep.setPreferredSize(new Dimension(15, 1));
0309 realBody.add(sep, BorderLayout.BEFORE_LINE_BEGINS);
0310 }
0311 realBody.add(body, BorderLayout.CENTER);
0312
0313 GridBagConstraints cons = new GridBagConstraints();
0314 cons.gridx = cons.gridy = 0;
0315 cons.gridwidth = GridBagConstraints.REMAINDER;
0316 cons.gridheight = 1;
0317 cons.anchor = DefaultLookup.getInt(optionPane, this ,
0318 "OptionPane.messageAnchor", GridBagConstraints.CENTER);
0319 cons.insets = new Insets(0, 0, 3, 0);
0320
0321 addMessageComponents(body, cons, getMessage(),
0322 getMaxCharactersPerLineCount(), false);
0323 top.add(realBody, BorderLayout.CENTER);
0324
0325 addIcon(top);
0326 return top;
0327 }
0328
0329 /**
0330 * Creates the appropriate object to represent <code>msg</code> and
0331 * places it into <code>container</code>. If <code>msg</code> is an
0332 * instance of Component, it is added directly, if it is an Icon,
0333 * a JLabel is created to represent it, otherwise a JLabel is
0334 * created for the string, if <code>d</code> is an Object[], this
0335 * method will be recursively invoked for the children.
0336 * <code>internallyCreated</code> is true if Objc is an instance
0337 * of Component and was created internally by this method (this is
0338 * used to correctly set hasCustomComponents only if !internallyCreated).
0339 */
0340 protected void addMessageComponents(Container container,
0341 GridBagConstraints cons, Object msg, int maxll,
0342 boolean internallyCreated) {
0343 if (msg == null) {
0344 return;
0345 }
0346 if (msg instanceof Component) {
0347 // To workaround problem where Gridbad will set child
0348 // to its minimum size if its preferred size will not fit
0349 // within allocated cells
0350 if (msg instanceof JScrollPane || msg instanceof JPanel) {
0351 cons.fill = GridBagConstraints.BOTH;
0352 cons.weighty = 1;
0353 } else {
0354 cons.fill = GridBagConstraints.HORIZONTAL;
0355 }
0356 cons.weightx = 1;
0357
0358 container.add((Component) msg, cons);
0359 cons.weightx = 0;
0360 cons.weighty = 0;
0361 cons.fill = GridBagConstraints.NONE;
0362 cons.gridy++;
0363 if (!internallyCreated) {
0364 hasCustomComponents = true;
0365 }
0366
0367 } else if (msg instanceof Object[]) {
0368 Object[] msgs = (Object[]) msg;
0369 for (int i = 0; i < msgs.length; i++) {
0370 addMessageComponents(container, cons, msgs[i], maxll,
0371 false);
0372 }
0373
0374 } else if (msg instanceof Icon) {
0375 JLabel label = new JLabel((Icon) msg, SwingConstants.CENTER);
0376 configureMessageLabel(label);
0377 addMessageComponents(container, cons, label, maxll, true);
0378
0379 } else {
0380 String s = msg.toString();
0381 int len = s.length();
0382 if (len <= 0) {
0383 return;
0384 }
0385 int nl = -1;
0386 int nll = 0;
0387
0388 if ((nl = s.indexOf(newline)) >= 0) {
0389 nll = newline.length();
0390 } else if ((nl = s.indexOf("\r\n")) >= 0) {
0391 nll = 2;
0392 } else if ((nl = s.indexOf('\n')) >= 0) {
0393 nll = 1;
0394 }
0395 if (nl >= 0) {
0396 // break up newlines
0397 if (nl == 0) {
0398 JPanel breakPanel = new JPanel() {
0399 public Dimension getPreferredSize() {
0400 Font f = getFont();
0401
0402 if (f != null) {
0403 return new Dimension(1, f.getSize() + 2);
0404 }
0405 return new Dimension(0, 0);
0406 }
0407 };
0408 breakPanel.setName("OptionPane.break");
0409 addMessageComponents(container, cons, breakPanel,
0410 maxll, true);
0411 } else {
0412 addMessageComponents(container, cons, s.substring(
0413 0, nl), maxll, false);
0414 }
0415 addMessageComponents(container, cons, s.substring(nl
0416 + nll), maxll, false);
0417
0418 } else if (len > maxll) {
0419 Container c = Box.createVerticalBox();
0420 c.setName("OptionPane.verticalBox");
0421 burstStringInto(c, s, maxll);
0422 addMessageComponents(container, cons, c, maxll, true);
0423
0424 } else {
0425 JLabel label;
0426 label = new JLabel(s, JLabel.LEADING);
0427 label.setName("OptionPane.label");
0428 configureMessageLabel(label);
0429 addMessageComponents(container, cons, label, maxll,
0430 true);
0431 }
0432 }
0433 }
0434
0435 /**
0436 * Returns the message to display from the JOptionPane the receiver is
0437 * providing the look and feel for.
0438 */
0439 protected Object getMessage() {
0440 inputComponent = null;
0441 if (optionPane != null) {
0442 if (optionPane.getWantsInput()) {
0443 /* Create a user component to capture the input. If the
0444 selectionValues are non null the component and there
0445 are < 20 values it'll be a combobox, if non null and
0446 >= 20, it'll be a list, otherwise it'll be a textfield. */
0447 Object message = optionPane.getMessage();
0448 Object[] sValues = optionPane.getSelectionValues();
0449 Object inputValue = optionPane
0450 .getInitialSelectionValue();
0451 JComponent toAdd;
0452
0453 if (sValues != null) {
0454 if (sValues.length < 20) {
0455 JComboBox cBox = new JComboBox();
0456
0457 cBox.setName("OptionPane.comboBox");
0458 for (int counter = 0, maxCounter = sValues.length; counter < maxCounter; counter++) {
0459 cBox.addItem(sValues[counter]);
0460 }
0461 if (inputValue != null) {
0462 cBox.setSelectedItem(inputValue);
0463 }
0464 inputComponent = cBox;
0465 toAdd = cBox;
0466
0467 } else {
0468 JList list = new JList(sValues);
0469 JScrollPane sp = new JScrollPane(list);
0470
0471 sp.setName("OptionPane.scrollPane");
0472 list.setName("OptionPane.list");
0473 list.setVisibleRowCount(10);
0474 list
0475 .setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
0476 if (inputValue != null)
0477 list.setSelectedValue(inputValue, true);
0478 list.addMouseListener(getHandler());
0479 toAdd = sp;
0480 inputComponent = list;
0481 }
0482
0483 } else {
0484 MultiplexingTextField tf = new MultiplexingTextField(
0485 20);
0486
0487 tf.setName("OptionPane.textField");
0488 tf.setKeyStrokes(new KeyStroke[] { KeyStroke
0489 .getKeyStroke("ENTER") });
0490 if (inputValue != null) {
0491 String inputString = inputValue.toString();
0492 tf.setText(inputString);
0493 tf.setSelectionStart(0);
0494 tf.setSelectionEnd(inputString.length());
0495 }
0496 tf.addActionListener(getHandler());
0497 toAdd = inputComponent = tf;
0498 }
0499
0500 Object[] newMessage;
0501
0502 if (message == null) {
0503 newMessage = new Object[1];
0504 newMessage[0] = toAdd;
0505
0506 } else {
0507 newMessage = new Object[2];
0508 newMessage[0] = message;
0509 newMessage[1] = toAdd;
0510 }
0511 return newMessage;
0512 }
0513 return optionPane.getMessage();
0514 }
0515 return null;
0516 }
0517
0518 /**
0519 * Creates and adds a JLabel representing the icon returned from
0520 * <code>getIcon</code> to <code>top</code>. This is messaged from
0521 * <code>createMessageArea</code>
0522 */
0523 protected void addIcon(Container top) {
0524 /* Create the icon. */
0525 Icon sideIcon = getIcon();
0526
0527 if (sideIcon != null) {
0528 JLabel iconLabel = new JLabel(sideIcon);
0529
0530 iconLabel.setName("OptionPane.iconLabel");
0531 iconLabel.setVerticalAlignment(SwingConstants.TOP);
0532 top.add(iconLabel, BorderLayout.BEFORE_LINE_BEGINS);
0533 }
0534 }
0535
0536 /**
0537 * Returns the icon from the JOptionPane the receiver is providing
0538 * the look and feel for, or the default icon as returned from
0539 * <code>getDefaultIcon</code>.
0540 */
0541 protected Icon getIcon() {
0542 Icon mIcon = (optionPane == null ? null : optionPane.getIcon());
0543
0544 if (mIcon == null && optionPane != null)
0545 mIcon = getIconForType(optionPane.getMessageType());
0546 return mIcon;
0547 }
0548
0549 /**
0550 * Returns the icon to use for the passed in type.
0551 */
0552 protected Icon getIconForType(int messageType) {
0553 if (messageType < 0 || messageType > 3)
0554 return null;
0555 String propertyName = null;
0556 switch (messageType) {
0557 case 0:
0558 propertyName = "OptionPane.errorIcon";
0559 break;
0560 case 1:
0561 propertyName = "OptionPane.informationIcon";
0562 break;
0563 case 2:
0564 propertyName = "OptionPane.warningIcon";
0565 break;
0566 case 3:
0567 propertyName = "OptionPane.questionIcon";
0568 break;
0569 }
0570 if (propertyName != null) {
0571 return (Icon) DefaultLookup.get(optionPane, this ,
0572 propertyName);
0573 }
0574 return null;
0575 }
0576
0577 /**
0578 * Returns the maximum number of characters to place on a line.
0579 */
0580 protected int getMaxCharactersPerLineCount() {
0581 return optionPane.getMaxCharactersPerLineCount();
0582 }
0583
0584 /**
0585 * Recursively creates new JLabel instances to represent <code>d</code>.
0586 * Each JLabel instance is added to <code>c</code>.
0587 */
0588 protected void burstStringInto(Container c, String d, int maxll) {
0589 // Primitive line wrapping
0590 int len = d.length();
0591 if (len <= 0)
0592 return;
0593 if (len > maxll) {
0594 int p = d.lastIndexOf(' ', maxll);
0595 if (p <= 0)
0596 p = d.indexOf(' ', maxll);
0597 if (p > 0 && p < len) {
0598 burstStringInto(c, d.substring(0, p), maxll);
0599 burstStringInto(c, d.substring(p + 1), maxll);
0600 return;
0601 }
0602 }
0603 JLabel label = new JLabel(d, JLabel.LEFT);
0604 label.setName("OptionPane.label");
0605 configureMessageLabel(label);
0606 c.add(label);
0607 }
0608
0609 protected Container createSeparator() {
0610 return null;
0611 }
0612
0613 /**
0614 * Creates and returns a Container containing the buttons. The buttons
0615 * are created by calling <code>getButtons</code>.
0616 */
0617 protected Container createButtonArea() {
0618 JPanel bottom = new JPanel();
0619 Border border = (Border) DefaultLookup.get(optionPane, this ,
0620 "OptionPane.buttonAreaBorder");
0621 bottom.setName("OptionPane.buttonArea");
0622 if (border != null) {
0623 bottom.setBorder(border);
0624 }
0625 bottom.setLayout(new ButtonAreaLayout(DefaultLookup.getBoolean(
0626 optionPane, this , "OptionPane.sameSizeButtons", true),
0627 DefaultLookup.getInt(optionPane, this ,
0628 "OptionPane.buttonPadding", 6), DefaultLookup
0629 .getInt(optionPane, this ,
0630 "OptionPane.buttonOrientation",
0631 SwingConstants.CENTER), DefaultLookup
0632 .getBoolean(optionPane, this ,
0633 "OptionPane.isYesLast", false)));
0634 addButtonComponents(bottom, getButtons(),
0635 getInitialValueIndex());
0636 return bottom;
0637 }
0638
0639 /**
0640 * Creates the appropriate object to represent each of the objects in
0641 * <code>buttons</code> and adds it to <code>container</code>. This
0642 * differs from addMessageComponents in that it will recurse on
0643 * <code>buttons</code> and that if button is not a Component
0644 * it will create an instance of JButton.
0645 */
0646 protected void addButtonComponents(Container container,
0647 Object[] buttons, int initialIndex) {
0648 if (buttons != null && buttons.length > 0) {
0649 boolean sizeButtonsToSame = getSizeButtonsToSameWidth();
0650 boolean createdAll = true;
0651 int numButtons = buttons.length;
0652 JButton[] createdButtons = null;
0653 int maxWidth = 0;
0654
0655 if (sizeButtonsToSame) {
0656 createdButtons = new JButton[numButtons];
0657 }
0658
0659 for (int counter = 0; counter < numButtons; counter++) {
0660 Object button = buttons[counter];
0661 Component newComponent;
0662
0663 if (button instanceof Component) {
0664 createdAll = false;
0665 newComponent = (Component) button;
0666 container.add(newComponent);
0667 hasCustomComponents = true;
0668
0669 } else {
0670 JButton aButton;
0671
0672 if (button instanceof ButtonFactory) {
0673 aButton = ((ButtonFactory) button)
0674 .createButton();
0675 } else if (button instanceof Icon)
0676 aButton = new JButton((Icon) button);
0677 else
0678 aButton = new JButton(button.toString());
0679
0680 aButton.setName("OptionPane.button");
0681 aButton.setMultiClickThreshhold(DefaultLookup
0682 .getInt(optionPane, this ,
0683 "OptionPane.buttonClickThreshhold",
0684 0));
0685 configureButton(aButton);
0686
0687 container.add(aButton);
0688
0689 ActionListener buttonListener = createButtonActionListener(counter);
0690 if (buttonListener != null) {
0691 aButton.addActionListener(buttonListener);
0692 }
0693 newComponent = aButton;
0694 }
0695 if (sizeButtonsToSame && createdAll
0696 && (newComponent instanceof JButton)) {
0697 createdButtons[counter] = (JButton) newComponent;
0698 maxWidth = Math.max(maxWidth, newComponent
0699 .getMinimumSize().width);
0700 }
0701 if (counter == initialIndex) {
0702 initialFocusComponent = newComponent;
0703 if (initialFocusComponent instanceof JButton) {
0704 JButton defaultB = (JButton) initialFocusComponent;
0705 defaultB
0706 .addHierarchyListener(new HierarchyListener() {
0707 public void hierarchyChanged(
0708 HierarchyEvent e) {
0709 if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED) != 0) {
0710 JButton defaultButton = (JButton) e
0711 .getComponent();
0712 JRootPane root = SwingUtilities
0713 .getRootPane(defaultButton);
0714 if (root != null) {
0715 root
0716 .setDefaultButton(defaultButton);
0717 }
0718 }
0719 }
0720 });
0721 }
0722 }
0723 }
0724 ((ButtonAreaLayout) container.getLayout())
0725 .setSyncAllWidths((sizeButtonsToSame && createdAll));
0726 /* Set the padding, windows seems to use 8 if <= 2 components,
0727 otherwise 4 is used. It may actually just be the size of the
0728 buttons is always the same, not sure. */
0729 if (DefaultLookup.getBoolean(optionPane, this ,
0730 "OptionPane.setButtonMargin", true)
0731 && sizeButtonsToSame && createdAll) {
0732 JButton aButton;
0733 int padSize;
0734
0735 padSize = (numButtons <= 2 ? 8 : 4);
0736
0737 for (int counter = 0; counter < numButtons; counter++) {
0738 aButton = createdButtons[counter];
0739 aButton
0740 .setMargin(new Insets(2, padSize, 2,
0741 padSize));
0742 }
0743 }
0744 }
0745 }
0746
0747 protected ActionListener createButtonActionListener(int buttonIndex) {
0748 return new ButtonActionListener(buttonIndex);
0749 }
0750
0751 /**
0752 * Returns the buttons to display from the JOptionPane the receiver is
0753 * providing the look and feel for. If the JOptionPane has options
0754 * set, they will be provided, otherwise if the optionType is
0755 * YES_NO_OPTION, yesNoOptions is returned, if the type is
0756 * YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise
0757 * defaultButtons are returned.
0758 */
0759 protected Object[] getButtons() {
0760 if (optionPane != null) {
0761 Object[] suppliedOptions = optionPane.getOptions();
0762
0763 if (suppliedOptions == null) {
0764 Object[] defaultOptions;
0765 int type = optionPane.getOptionType();
0766 Locale l = optionPane.getLocale();
0767 int minimumWidth = DefaultLookup.getInt(optionPane,
0768 this , "OptionPane.buttonMinimumWidth", -1);
0769 if (type == JOptionPane.YES_NO_OPTION) {
0770 defaultOptions = new ButtonFactory[2];
0771 defaultOptions[0] = new ButtonFactory(UIManager
0772 .getString("OptionPane.yesButtonText", l),
0773 getMnemonic("OptionPane.yesButtonMnemonic",
0774 l), (Icon) DefaultLookup.get(
0775 optionPane, this ,
0776 "OptionPane.yesIcon"), minimumWidth);
0777 defaultOptions[1] = new ButtonFactory(UIManager
0778 .getString("OptionPane.noButtonText", l),
0779 getMnemonic("OptionPane.noButtonMnemonic",
0780 l), (Icon) DefaultLookup.get(
0781 optionPane, this ,
0782 "OptionPane.noIcon"), minimumWidth);
0783 } else if (type == JOptionPane.YES_NO_CANCEL_OPTION) {
0784 defaultOptions = new ButtonFactory[3];
0785 defaultOptions[0] = new ButtonFactory(UIManager
0786 .getString("OptionPane.yesButtonText", l),
0787 getMnemonic("OptionPane.yesButtonMnemonic",
0788 l), (Icon) DefaultLookup.get(
0789 optionPane, this ,
0790 "OptionPane.yesIcon"), minimumWidth);
0791 defaultOptions[1] = new ButtonFactory(UIManager
0792 .getString("OptionPane.noButtonText", l),
0793 getMnemonic("OptionPane.noButtonMnemonic",
0794 l), (Icon) DefaultLookup.get(
0795 optionPane, this ,
0796 "OptionPane.noIcon"), minimumWidth);
0797 defaultOptions[2] = new ButtonFactory(
0798 UIManager.getString(
0799 "OptionPane.cancelButtonText", l),
0800 getMnemonic(
0801 "OptionPane.cancelButtonMnemonic",
0802 l), (Icon) DefaultLookup.get(
0803 optionPane, this ,
0804 "OptionPane.cancelIcon"),
0805 minimumWidth);
0806 } else if (type == JOptionPane.OK_CANCEL_OPTION) {
0807 defaultOptions = new ButtonFactory[2];
0808 defaultOptions[0] = new ButtonFactory(UIManager
0809 .getString("OptionPane.okButtonText", l),
0810 getMnemonic("OptionPane.okButtonMnemonic",
0811 l), (Icon) DefaultLookup.get(
0812 optionPane, this ,
0813 "OptionPane.okIcon"), minimumWidth);
0814 defaultOptions[1] = new ButtonFactory(
0815 UIManager.getString(
0816 "OptionPane.cancelButtonText", l),
0817 getMnemonic(
0818 "OptionPane.cancelButtonMnemonic",
0819 l), (Icon) DefaultLookup.get(
0820 optionPane, this ,
0821 "OptionPane.cancelIcon"),
0822 minimumWidth);
0823 } else {
0824 defaultOptions = new ButtonFactory[1];
0825 defaultOptions[0] = new ButtonFactory(UIManager
0826 .getString("OptionPane.okButtonText", l),
0827 getMnemonic("OptionPane.okButtonMnemonic",
0828 l), (Icon) DefaultLookup.get(
0829 optionPane, this ,
0830 "OptionPane.okIcon"), minimumWidth);
0831 }
0832 return defaultOptions;
0833
0834 }
0835 return suppliedOptions;
0836 }
0837 return null;
0838 }
0839
0840 private int getMnemonic(String key, Locale l) {
0841 String value = (String) UIManager.get(key, l);
0842
0843 if (value == null) {
0844 return 0;
0845 }
0846 try {
0847 return Integer.parseInt(value);
0848 } catch (NumberFormatException nfe) {
0849 }
0850 return 0;
0851 }
0852
0853 /**
0854 * Returns true, basic L&F wants all the buttons to have the same
0855 * width.
0856 */
0857 protected boolean getSizeButtonsToSameWidth() {
0858 return true;
0859 }
0860
0861 /**
0862 * Returns the initial index into the buttons to select. The index
0863 * is calculated from the initial value from the JOptionPane and
0864 * options of the JOptionPane or 0.
0865 */
0866 protected int getInitialValueIndex() {
0867 if (optionPane != null) {
0868 Object iv = optionPane.getInitialValue();
0869 Object[] options = optionPane.getOptions();
0870
0871 if (options == null) {
0872 return 0;
0873 } else if (iv != null) {
0874 for (int counter = options.length - 1; counter >= 0; counter--) {
0875 if (options[counter].equals(iv))
0876 return counter;
0877 }
0878 }
0879 }
0880 return -1;
0881 }
0882
0883 /**
0884 * Sets the input value in the option pane the receiver is providing
0885 * the look and feel for based on the value in the inputComponent.
0886 */
0887 protected void resetInputValue() {
0888 if (inputComponent != null
0889 && (inputComponent instanceof JTextField)) {
0890 optionPane.setInputValue(((JTextField) inputComponent)
0891 .getText());
0892
0893 } else if (inputComponent != null
0894 && (inputComponent instanceof JComboBox)) {
0895 optionPane.setInputValue(((JComboBox) inputComponent)
0896 .getSelectedItem());
0897 } else if (inputComponent != null) {
0898 optionPane.setInputValue(((JList) inputComponent)
0899 .getSelectedValue());
0900 }
0901 }
0902
0903 /**
0904 * If inputComponent is non-null, the focus is requested on that,
0905 * otherwise request focus on the default value
0906 */
0907 public void selectInitialValue(JOptionPane op) {
0908 if (inputComponent != null)
0909 inputComponent.requestFocus();
0910 else {
0911 if (initialFocusComponent != null)
0912 initialFocusComponent.requestFocus();
0913
0914 if (initialFocusComponent instanceof JButton) {
0915 JRootPane root = SwingUtilities
0916 .getRootPane(initialFocusComponent);
0917 if (root != null) {
0918 root
0919 .setDefaultButton((JButton) initialFocusComponent);
0920 }
0921 }
0922 }
0923 }
0924
0925 /**
0926 * Returns true if in the last call to validateComponent the message
0927 * or buttons contained a subclass of Component.
0928 */
0929 public boolean containsCustomComponents(JOptionPane op) {
0930 return hasCustomComponents;
0931 }
0932
0933 /**
0934 * <code>ButtonAreaLayout</code> behaves in a similar manner to
0935 * <code>FlowLayout</code>. It lays out all components from left to
0936 * right. If <code>syncAllWidths</code> is true, the widths of each
0937 * component will be set to the largest preferred size width.
0938 *
0939 * This inner class is marked "public" due to a compiler bug.
0940 * This class should be treated as a "protected" inner class.
0941 * Instantiate it only within subclasses of BasicOptionPaneUI.
0942 */
0943 public static class ButtonAreaLayout implements LayoutManager {
0944 protected boolean syncAllWidths;
0945 protected int padding;
0946 /** If true, children are lumped together in parent. */
0947 protected boolean centersChildren;
0948 private int orientation;
0949 private boolean reverseButtons;
0950 /**
0951 * Indicates whether or not centersChildren should be used vs
0952 * the orientation. This is done for backward compatability
0953 * for subclassers.
0954 */
0955 private boolean useOrientation;
0956
0957 public ButtonAreaLayout(boolean syncAllWidths, int padding) {
0958 this .syncAllWidths = syncAllWidths;
0959 this .padding = padding;
0960 centersChildren = true;
0961 useOrientation = false;
0962 }
0963
0964 ButtonAreaLayout(boolean syncAllSizes, int padding,
0965 int orientation, boolean reverseButtons) {
0966 this (syncAllSizes, padding);
0967 useOrientation = true;
0968 this .orientation = orientation;
0969 this .reverseButtons = reverseButtons;
0970 }
0971
0972 public void setSyncAllWidths(boolean newValue) {
0973 syncAllWidths = newValue;
0974 }
0975
0976 public boolean getSyncAllWidths() {
0977 return syncAllWidths;
0978 }
0979
0980 public void setPadding(int newPadding) {
0981 this .padding = newPadding;
0982 }
0983
0984 public int getPadding() {
0985 return padding;
0986 }
0987
0988 public void setCentersChildren(boolean newValue) {
0989 centersChildren = newValue;
0990 useOrientation = false;
0991 }
0992
0993 public boolean getCentersChildren() {
0994 return centersChildren;
0995 }
0996
0997 private int getOrientation(Container container) {
0998 if (!useOrientation) {
0999 return SwingConstants.CENTER;
1000 }
1001 if (container.getComponentOrientation().isLeftToRight()) {
1002 return orientation;
1003 }
1004 switch (orientation) {
1005 case SwingConstants.LEFT:
1006 return SwingConstants.RIGHT;
1007 case SwingConstants.RIGHT:
1008 return SwingConstants.LEFT;
1009 case SwingConstants.CENTER:
1010 return SwingConstants.CENTER;
1011 }
1012 return SwingConstants.LEFT;
1013 }
1014
1015 public void addLayoutComponent(String string, Component comp) {
1016 }
1017
1018 public void layoutContainer(Container container) {
1019 Component[] children = container.getComponents();
1020
1021 if (children != null && children.length > 0) {
1022 int numChildren = children.length;
1023 Insets insets = container.getInsets();
1024 int maxWidth = 0;
1025 int maxHeight = 0;
1026 int totalButtonWidth = 0;
1027 int x = 0;
1028 int xOffset = 0;
1029 boolean ltr = container.getComponentOrientation()
1030 .isLeftToRight();
1031 boolean reverse = (ltr) ? reverseButtons
1032 : !reverseButtons;
1033
1034 for (int counter = 0; counter < numChildren; counter++) {
1035 Dimension pref = children[counter]
1036 .getPreferredSize();
1037 maxWidth = Math.max(maxWidth, pref.width);
1038 maxHeight = Math.max(maxHeight, pref.height);
1039 totalButtonWidth += pref.width;
1040 }
1041 if (getSyncAllWidths()) {
1042 totalButtonWidth = maxWidth * numChildren;
1043 }
1044 totalButtonWidth += (numChildren - 1) * padding;
1045
1046 switch (getOrientation(container)) {
1047 case SwingConstants.LEFT:
1048 x = insets.left;
1049 break;
1050 case SwingConstants.RIGHT:
1051 x = container.getWidth() - insets.right
1052 - totalButtonWidth;
1053 break;
1054 case SwingConstants.CENTER:
1055 if (getCentersChildren() || numChildren < 2) {
1056 x = (container.getWidth() - totalButtonWidth) / 2;
1057 } else {
1058 x = insets.left;
1059 if (getSyncAllWidths()) {
1060 xOffset = (container.getWidth()
1061 - insets.left - insets.right - totalButtonWidth)
1062 / (numChildren - 1) + maxWidth;
1063 } else {
1064 xOffset = (container.getWidth()
1065 - insets.left - insets.right - totalButtonWidth)
1066 / (numChildren - 1);
1067 }
1068 }
1069 break;
1070 }
1071
1072 for (int counter = 0; counter < numChildren; counter++) {
1073 int index = (reverse) ? numChildren - counter - 1
1074 : counter;
1075 Dimension pref = children[index].getPreferredSize();
1076
1077 if (getSyncAllWidths()) {
1078 children[index].setBounds(x, insets.top,
1079 maxWidth, maxHeight);
1080 } else {
1081 children[index].setBounds(x, insets.top,
1082 pref.width, pref.height);
1083 }
1084 if (xOffset != 0) {
1085 x += xOffset;
1086 } else {
1087 x += children[index].getWidth() + padding;
1088 }
1089 }
1090 }
1091 }
1092
1093 public Dimension minimumLayoutSize(Container c) {
1094 if (c != null) {
1095 Component[] children = c.getComponents();
1096
1097 if (children != null && children.length > 0) {
1098 Dimension aSize;
1099 int numChildren = children.length;
1100 int height = 0;
1101 Insets cInsets = c.getInsets();
1102 int extraHeight = cInsets.top + cInsets.bottom;
1103 int extraWidth = cInsets.left + cInsets.right;
1104
1105 if (syncAllWidths) {
1106 int maxWidth = 0;
1107
1108 for (int counter = 0; counter < numChildren; counter++) {
1109 aSize = children[counter]
1110 .getPreferredSize();
1111 height = Math.max(height, aSize.height);
1112 maxWidth = Math.max(maxWidth, aSize.width);
1113 }
1114 return new Dimension(extraWidth
1115 + (maxWidth * numChildren)
1116 + (numChildren - 1) * padding,
1117 extraHeight + height);
1118 } else {
1119 int totalWidth = 0;
1120
1121 for (int counter = 0; counter < numChildren; counter++) {
1122 aSize = children[counter]
1123 .getPreferredSize();
1124 height = Math.max(height, aSize.height);
1125 totalWidth += aSize.width;
1126 }
1127 totalWidth += ((numChildren - 1) * padding);
1128 return new Dimension(extraWidth + totalWidth,
1129 extraHeight + height);
1130 }
1131 }
1132 }
1133 return new Dimension(0, 0);
1134 }
1135
1136 public Dimension preferredLayoutSize(Container c) {
1137 return minimumLayoutSize(c);
1138 }
1139
1140 public void removeLayoutComponent(Component c) {
1141 }
1142 }
1143
1144 /**
1145 * This inner class is marked "public" due to a compiler bug.
1146 * This class should be treated as a "protected" inner class.
1147 * Instantiate it only within subclasses of BasicOptionPaneUI.
1148 */
1149 public class PropertyChangeHandler implements
1150 PropertyChangeListener {
1151 /**
1152 * If the source of the PropertyChangeEvent <code>e</code> equals the
1153 * optionPane and is one of the ICON_PROPERTY, MESSAGE_PROPERTY,
1154 * OPTIONS_PROPERTY or INITIAL_VALUE_PROPERTY,
1155 * validateComponent is invoked.
1156 */
1157 public void propertyChange(PropertyChangeEvent e) {
1158 getHandler().propertyChange(e);
1159 }
1160 }
1161
1162 /**
1163 * Configures any necessary colors/fonts for the specified label
1164 * used representing the message.
1165 */
1166 private void configureMessageLabel(JLabel label) {
1167 Color color = (Color) DefaultLookup.get(optionPane, this ,
1168 "OptionPane.messageForeground");
1169 if (color != null) {
1170 label.setForeground(color);
1171 }
1172 Font messageFont = (Font) DefaultLookup.get(optionPane, this ,
1173 "OptionPane.messageFont");
1174 if (messageFont != null) {
1175 label.setFont(messageFont);
1176 }
1177 }
1178
1179 /**
1180 * Configures any necessary colors/fonts for the specified button
1181 * used representing the button portion of the optionpane.
1182 */
1183 private void configureButton(JButton button) {
1184 Font buttonFont = (Font) DefaultLookup.get(optionPane, this ,
1185 "OptionPane.buttonFont");
1186 if (buttonFont != null) {
1187 button.setFont(buttonFont);
1188 }
1189 }
1190
1191 /**
1192 * This inner class is marked "public" due to a compiler bug.
1193 * This class should be treated as a "protected" inner class.
1194 * Instantiate it only within subclasses of BasicOptionPaneUI.
1195 */
1196 public class ButtonActionListener implements ActionListener {
1197 protected int buttonIndex;
1198
1199 public ButtonActionListener(int buttonIndex) {
1200 this .buttonIndex = buttonIndex;
1201 }
1202
1203 public void actionPerformed(ActionEvent e) {
1204 if (optionPane != null) {
1205 int optionType = optionPane.getOptionType();
1206 Object[] options = optionPane.getOptions();
1207
1208 /* If the option pane takes input, then store the input value
1209 * if custom options were specified, if the option type is
1210 * DEFAULT_OPTION, OR if option type is set to a predefined
1211 * one and the user chose the affirmative answer.
1212 */
1213 if (inputComponent != null) {
1214 if (options != null
1215 || optionType == JOptionPane.DEFAULT_OPTION
1216 || ((optionType == JOptionPane.YES_NO_OPTION
1217 || optionType == JOptionPane.YES_NO_CANCEL_OPTION || optionType == JOptionPane.OK_CANCEL_OPTION) && buttonIndex == 0)) {
1218 resetInputValue();
1219 }
1220 }
1221 if (options == null) {
1222 if (optionType == JOptionPane.OK_CANCEL_OPTION
1223 && buttonIndex == 1) {
1224 optionPane.setValue(new Integer(2));
1225
1226 } else {
1227 optionPane.setValue(new Integer(buttonIndex));
1228 }
1229 } else {
1230 optionPane.setValue(options[buttonIndex]);
1231 }
1232 }
1233 }
1234 }
1235
1236 private class Handler implements ActionListener, MouseListener,
1237 PropertyChangeListener {
1238 //
1239 // ActionListener
1240 //
1241 public void actionPerformed(ActionEvent e) {
1242 optionPane.setInputValue(((JTextField) e.getSource())
1243 .getText());
1244 }
1245
1246 //
1247 // MouseListener
1248 //
1249 public void mouseClicked(MouseEvent e) {
1250 }
1251
1252 public void mouseReleased(MouseEvent e) {
1253 }
1254
1255 public void mouseEntered(MouseEvent e) {
1256 }
1257
1258 public void mouseExited(MouseEvent e) {
1259 }
1260
1261 public void mousePressed(MouseEvent e) {
1262 if (e.getClickCount() == 2) {
1263 JList list = (JList) e.getSource();
1264 int index = list.locationToIndex(e.getPoint());
1265
1266 optionPane.setInputValue(list.getModel().getElementAt(
1267 index));
1268 }
1269 }
1270
1271 //
1272 // PropertyChangeListener
1273 //
1274 public void propertyChange(PropertyChangeEvent e) {
1275 if (e.getSource() == optionPane) {
1276 // Option Pane Auditory Cue Activation
1277 // only respond to "ancestor" changes
1278 // the idea being that a JOptionPane gets a JDialog when it is
1279 // set to appear and loses it's JDialog when it is dismissed.
1280 if ("ancestor" == e.getPropertyName()) {
1281 JOptionPane op = (JOptionPane) e.getSource();
1282 boolean isComingUp;
1283
1284 // if the old value is null, then the JOptionPane is being
1285 // created since it didn't previously have an ancestor.
1286 if (e.getOldValue() == null) {
1287 isComingUp = true;
1288 } else {
1289 isComingUp = false;
1290 }
1291
1292 // figure out what to do based on the message type
1293 switch (op.getMessageType()) {
1294 case JOptionPane.PLAIN_MESSAGE:
1295 if (isComingUp) {
1296 BasicLookAndFeel.playSound(optionPane,
1297 "OptionPane.informationSound");
1298 }
1299 break;
1300 case JOptionPane.QUESTION_MESSAGE:
1301 if (isComingUp) {
1302 BasicLookAndFeel.playSound(optionPane,
1303 "OptionPane.questionSound");
1304 }
1305 break;
1306 case JOptionPane.INFORMATION_MESSAGE:
1307 if (isComingUp) {
1308 BasicLookAndFeel.playSound(optionPane,
1309 "OptionPane.informationSound");
1310 }
1311 break;
1312 case JOptionPane.WARNING_MESSAGE:
1313 if (isComingUp) {
1314 BasicLookAndFeel.playSound(optionPane,
1315 "OptionPane.warningSound");
1316 }
1317 break;
1318 case JOptionPane.ERROR_MESSAGE:
1319 if (isComingUp) {
1320 BasicLookAndFeel.playSound(optionPane,
1321 "OptionPane.errorSound");
1322 }
1323 break;
1324 default:
1325 System.err
1326 .println("Undefined JOptionPane type: "
1327 + op.getMessageType());
1328 break;
1329 }
1330 }
1331 // Visual activity
1332 String changeName = e.getPropertyName();
1333
1334 if (changeName == JOptionPane.OPTIONS_PROPERTY
1335 || changeName == JOptionPane.INITIAL_VALUE_PROPERTY
1336 || changeName == JOptionPane.ICON_PROPERTY
1337 || changeName == JOptionPane.MESSAGE_TYPE_PROPERTY
1338 || changeName == JOptionPane.OPTION_TYPE_PROPERTY
1339 || changeName == JOptionPane.MESSAGE_PROPERTY
1340 || changeName == JOptionPane.SELECTION_VALUES_PROPERTY
1341 || changeName == JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY
1342 || changeName == JOptionPane.WANTS_INPUT_PROPERTY) {
1343 uninstallComponents();
1344 installComponents();
1345 optionPane.validate();
1346 } else if (changeName == "componentOrientation") {
1347 ComponentOrientation o = (ComponentOrientation) e
1348 .getNewValue();
1349 JOptionPane op = (JOptionPane) e.getSource();
1350 if (o != (ComponentOrientation) e.getOldValue()) {
1351 op.applyComponentOrientation(o);
1352 }
1353 }
1354 }
1355 }
1356 }
1357
1358 //
1359 // Classes used when optionPane.getWantsInput returns true.
1360 //
1361
1362 /**
1363 * A JTextField that allows you to specify an array of KeyStrokes that
1364 * that will have their bindings processed regardless of whether or
1365 * not they are registered on the JTextField. This is used as we really
1366 * want the ActionListener to be notified so that we can push the
1367 * change to the JOptionPane, but we also want additional bindings
1368 * (those of the JRootPane) to be processed as well.
1369 */
1370 private static class MultiplexingTextField extends JTextField {
1371 private KeyStroke[] strokes;
1372
1373 MultiplexingTextField(int cols) {
1374 super (cols);
1375 }
1376
1377 /**
1378 * Sets the KeyStrokes that will be additional processed for
1379 * ancestor bindings.
1380 */
1381 void setKeyStrokes(KeyStroke[] strokes) {
1382 this .strokes = strokes;
1383 }
1384
1385 protected boolean processKeyBinding(KeyStroke ks, KeyEvent e,
1386 int condition, boolean pressed) {
1387 boolean processed = super .processKeyBinding(ks, e,
1388 condition, pressed);
1389
1390 if (processed
1391 && condition != JComponent.WHEN_IN_FOCUSED_WINDOW) {
1392 for (int counter = strokes.length - 1; counter >= 0; counter--) {
1393 if (strokes[counter].equals(ks)) {
1394 // Returning false will allow further processing
1395 // of the bindings, eg our parent Containers will get a
1396 // crack at them.
1397 return false;
1398 }
1399 }
1400 }
1401 return processed;
1402 }
1403 }
1404
1405 /**
1406 * Registered in the ActionMap. Sets the value of the option pane
1407 * to <code>JOptionPane.CLOSED_OPTION</code>.
1408 */
1409 private static class Actions extends UIAction {
1410 private static final String CLOSE = "close";
1411
1412 Actions(String key) {
1413 super (key);
1414 }
1415
1416 public void actionPerformed(ActionEvent e) {
1417 if (getName() == CLOSE) {
1418 JOptionPane optionPane = (JOptionPane) e.getSource();
1419
1420 optionPane.setValue(new Integer(
1421 JOptionPane.CLOSED_OPTION));
1422 }
1423 }
1424 }
1425
1426 /**
1427 * This class is used to create the default buttons. This indirection is
1428 * used so that addButtonComponents can tell which Buttons were created
1429 * by us vs subclassers or from the JOptionPane itself.
1430 */
1431 private static class ButtonFactory {
1432 private String text;
1433 private int mnemonic;
1434 private Icon icon;
1435 private int minimumWidth = -1;
1436
1437 ButtonFactory(String text, int mnemonic, Icon icon,
1438 int minimumWidth) {
1439 this .text = text;
1440 this .mnemonic = mnemonic;
1441 this .icon = icon;
1442 this .minimumWidth = minimumWidth;
1443 }
1444
1445 JButton createButton() {
1446 JButton button = null;
1447
1448 if (minimumWidth > 0) {
1449 button = new ConstrainedButton(text, minimumWidth);
1450 } else {
1451 button = new JButton(text);
1452 }
1453 if (icon != null) {
1454 button.setIcon(icon);
1455 }
1456 if (mnemonic != 0) {
1457 button.setMnemonic(mnemonic);
1458 }
1459 return button;
1460 }
1461
1462 private static class ConstrainedButton extends JButton {
1463 int minimumWidth;
1464
1465 ConstrainedButton(String text, int minimumWidth) {
1466 super (text);
1467 this .minimumWidth = minimumWidth;
1468 }
1469
1470 public Dimension getMinimumSize() {
1471 Dimension min = super .getMinimumSize();
1472 min.width = Math.max(min.width, minimumWidth);
1473 return min;
1474 }
1475
1476 public Dimension getPreferredSize() {
1477 Dimension pref = super.getPreferredSize();
1478 pref.width = Math.max(pref.width, minimumWidth);
1479 return pref;
1480 }
1481 }
1482 }
1483 }
|