1. /*
  2. * @(#)BasicOptionPaneUI.java 1.36 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.basic;
  11. import javax.swing.border.Border;
  12. import javax.swing.border.EmptyBorder;
  13. import javax.swing.*;
  14. import javax.swing.event.*;
  15. import javax.swing.plaf.ActionMapUIResource;
  16. import javax.swing.plaf.ComponentUI;
  17. import javax.swing.plaf.OptionPaneUI;
  18. import java.awt.*;
  19. import java.awt.event.*;
  20. import java.beans.PropertyChangeEvent;
  21. import java.beans.PropertyChangeListener;
  22. /**
  23. * Provides the basic look and feel for a JOptionPane.
  24. * BasicMessagePaneUI provides a means to place an icon, message and
  25. * buttons into a Container. The layout will look like:<p>
  26. * <pre>
  27. * ------------------
  28. * | i | message |
  29. * | c | message |
  30. * | o | message |
  31. * | n | message |
  32. * ------------------
  33. * | buttons |
  34. * |________________|
  35. * </pre>
  36. * icon is an instance of Icon that is wraped inside a JLabel.
  37. * The message is an opaque object and is tested for the following:
  38. * if the message is a Component it is added to the Container, if
  39. * it is an Icon it is wrapped inside a JLabel and added to the
  40. * Container otherwise it is wrapped inside a JLabel.
  41. * <p>
  42. * The Container, message, icon, and buttons are all determined from
  43. * abstract methods.
  44. *
  45. * @version 1.36 02/02/00
  46. * @author James Gosling
  47. * @author Scott Violet
  48. * @author Amy Fowler
  49. */
  50. public class BasicOptionPaneUI extends OptionPaneUI {
  51. public static final int MinimumWidth = 262;
  52. public static final int MinimumHeight = 90;
  53. /** JOptionPane that the reciever is providing the look and feel for. */
  54. protected JOptionPane optionPane;
  55. protected Dimension minimumSize;
  56. /** JComponent provide for input if optionPane.getWantsInput() returns
  57. * true. */
  58. protected JComponent inputComponent;
  59. /** Component to receive focus when messaged with selectInitialValue. */
  60. protected Component initialFocusComponent;
  61. /** This is set to true in validateComponent if a Component is contained
  62. * in either the message or the buttons. */
  63. protected boolean hasCustomComponents;
  64. protected PropertyChangeListener propertyChangeListener;
  65. /**
  66. * Creates a new BasicOptionPaneUI instance.
  67. */
  68. public static ComponentUI createUI(JComponent x) {
  69. return new BasicOptionPaneUI();
  70. }
  71. /**
  72. * Installs the reciever as the L&F for the passed in JOptionPane
  73. */
  74. public void installUI(JComponent c) {
  75. optionPane = (JOptionPane)c;
  76. installDefaults();
  77. optionPane.setLayout(createLayoutManager());
  78. installComponents();
  79. installListeners();
  80. installKeyboardActions();
  81. }
  82. /**
  83. * Removes the receiver from the L&F controller of the passed in split
  84. * pane.
  85. */
  86. public void uninstallUI(JComponent c) {
  87. uninstallComponents();
  88. optionPane.setLayout(null);
  89. uninstallKeyboardActions();
  90. uninstallListeners();
  91. uninstallDefaults();
  92. optionPane = null;
  93. }
  94. protected void installDefaults() {
  95. LookAndFeel.installColorsAndFont(optionPane, "OptionPane.background",
  96. "OptionPane.foreground", "OptionPane.font");
  97. LookAndFeel.installBorder(optionPane, "OptionPane.border");
  98. minimumSize = UIManager.getDimension("OptionPane.minimumSize");
  99. optionPane.setOpaque(true);
  100. }
  101. protected void uninstallDefaults() {
  102. LookAndFeel.uninstallBorder(optionPane);
  103. }
  104. protected void installComponents() {
  105. optionPane.add(createMessageArea());
  106. Container separator = createSeparator();
  107. if (separator != null) {
  108. optionPane.add(separator);
  109. }
  110. optionPane.add(createButtonArea());
  111. }
  112. protected void uninstallComponents() {
  113. hasCustomComponents = false;
  114. inputComponent = null;
  115. initialFocusComponent = null;
  116. optionPane.removeAll();
  117. }
  118. protected LayoutManager createLayoutManager() {
  119. return new BoxLayout(optionPane, BoxLayout.Y_AXIS);
  120. }
  121. protected void installListeners() {
  122. if ((propertyChangeListener = createPropertyChangeListener()) != null) {
  123. optionPane.addPropertyChangeListener(propertyChangeListener);
  124. }
  125. }
  126. protected void uninstallListeners() {
  127. if (propertyChangeListener != null) {
  128. optionPane.removePropertyChangeListener(propertyChangeListener);
  129. propertyChangeListener = null;
  130. }
  131. }
  132. protected PropertyChangeListener createPropertyChangeListener() {
  133. return new PropertyChangeHandler();
  134. }
  135. protected void installKeyboardActions() {
  136. InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
  137. SwingUtilities.replaceUIInputMap(optionPane, JComponent.
  138. WHEN_IN_FOCUSED_WINDOW, map);
  139. ActionMap actionMap = getActionMap();
  140. SwingUtilities.replaceUIActionMap(optionPane, actionMap);
  141. }
  142. protected void uninstallKeyboardActions() {
  143. SwingUtilities.replaceUIInputMap(optionPane, JComponent.
  144. WHEN_IN_FOCUSED_WINDOW, null);
  145. SwingUtilities.replaceUIActionMap(optionPane, null);
  146. }
  147. InputMap getInputMap(int condition) {
  148. if (condition == JComponent.WHEN_IN_FOCUSED_WINDOW) {
  149. Object[] bindings = (Object[])UIManager.get
  150. ("OptionPane.windowBindings");
  151. if (bindings != null) {
  152. return LookAndFeel.makeComponentInputMap(optionPane, bindings);
  153. }
  154. }
  155. return null;
  156. }
  157. ActionMap getActionMap() {
  158. ActionMap map = (ActionMap)UIManager.get("OptionPane.actionMap");
  159. if (map == null) {
  160. map = createActionMap();
  161. if (map != null) {
  162. UIManager.put("OptionPane.actionMap", map);
  163. }
  164. }
  165. return map;
  166. }
  167. ActionMap createActionMap() {
  168. ActionMap map = new ActionMapUIResource();
  169. map.put("close", new CloseAction());
  170. return map;
  171. }
  172. /**
  173. * Returns the minimum size the option pane should be. Primarily
  174. * provided for subclassers wishin to offer a different minimum size.
  175. */
  176. public Dimension getMinimumOptionPaneSize() {
  177. if (minimumSize == null) {
  178. //minimumSize = UIManager.getDimension("OptionPane.minimumSize");
  179. // this is called before defaults initialized?!!!
  180. return new Dimension(MinimumWidth, MinimumHeight);
  181. }
  182. return new Dimension(minimumSize.width,
  183. minimumSize.height);
  184. }
  185. /**
  186. * If c is the JOptionPane the reciever is contained in, the preferred
  187. * size that is returned is the maximum of the preferred size of
  188. * the LayoutManager for the JOptionPane, and
  189. * <code>getMinimumOptionPaneSize</code>.
  190. */
  191. public Dimension getPreferredSize(JComponent c) {
  192. if ((JOptionPane)c == optionPane) {
  193. Dimension ourMin = getMinimumOptionPaneSize();
  194. LayoutManager lm = c.getLayout();
  195. if (lm != null) {
  196. Dimension lmSize = lm.preferredLayoutSize(c);
  197. if (ourMin != null)
  198. return new Dimension
  199. (Math.max(lmSize.width, ourMin.width),
  200. Math.max(lmSize.height, ourMin.height));
  201. return lmSize;
  202. }
  203. return ourMin;
  204. }
  205. return null;
  206. }
  207. /**
  208. * Messages getPreferredSize.
  209. */
  210. public Dimension getMinimumSize(JComponent c) {
  211. return getPreferredSize(c);
  212. }
  213. /**
  214. * Messages getPreferredSize.
  215. */
  216. public Dimension getMaximumSize(JComponent c) {
  217. return getPreferredSize(c);
  218. }
  219. /**
  220. * Messaged from installComponents to create a Container containing the
  221. * body of the message. The icon is the created by calling
  222. * <code>addIcon</code>.
  223. */
  224. protected Container createMessageArea() {
  225. JPanel top = new JPanel();
  226. top.setBorder(UIManager.getBorder("OptionPane.messageAreaBorder"));
  227. top.setLayout(new BorderLayout());
  228. /* Fill the body. */
  229. Container body = new JPanel() {};
  230. Container realBody = new JPanel() {};
  231. Container sep = new JPanel() {
  232. public Dimension getPreferredSize() {
  233. return new Dimension(15, 1);
  234. }
  235. };
  236. realBody.setLayout(new BorderLayout());
  237. realBody.add(sep, BorderLayout.WEST);
  238. realBody.add(body, BorderLayout.CENTER);
  239. body.setLayout(new GridBagLayout());
  240. GridBagConstraints cons = new GridBagConstraints();
  241. cons.gridx = cons.gridy = 0;
  242. cons.gridwidth = GridBagConstraints.REMAINDER;
  243. cons.gridheight = 1;
  244. cons.anchor = GridBagConstraints.WEST;
  245. cons.insets = new Insets(0,0,3,0);
  246. addMessageComponents(body, cons, getMessage(),
  247. getMaxCharactersPerLineCount(), false);
  248. top.add(realBody, BorderLayout.CENTER);
  249. addIcon(top);
  250. return top;
  251. }
  252. /**
  253. * Creates the appropriate object to represent <code>msg</code> and
  254. * places it into <code>container</code>. If <code>msg</code> is an
  255. * instance of Component, it is added directly, if it is an Icon,
  256. * a JLabel is created to represent it, otherwise a JLabel is
  257. * created for the string, if <code>d</code> is an Object[], this
  258. * method will be recursively invoked for the children.
  259. * <code>internallyCreated</code> is true if Objc is an instance
  260. * of Component and was created internally by this method (this is
  261. * used to correctly set hasCustomComponents only if !internallyCreated).
  262. */
  263. protected void addMessageComponents(Container container,
  264. GridBagConstraints cons,
  265. Object msg, int maxll,
  266. boolean internallyCreated) {
  267. if (msg == null) {
  268. return;
  269. }
  270. if (msg instanceof Component) {
  271. // To workaround problem where Gridbad will set child
  272. // to its minimum size if its preferred size will not fit
  273. // within allocated cells
  274. if (msg instanceof JScrollPane || msg instanceof JPanel) {
  275. cons.fill = GridBagConstraints.BOTH;
  276. cons.weighty = 1;
  277. } else {
  278. cons.fill = GridBagConstraints.HORIZONTAL;
  279. }
  280. cons.weightx = 1;
  281. container.add((Component) msg, cons);
  282. cons.weightx = 0;
  283. cons.weighty = 0;
  284. cons.fill = GridBagConstraints.NONE;
  285. cons.gridy++;
  286. if (!internallyCreated) {
  287. hasCustomComponents = true;
  288. }
  289. } else if (msg instanceof Object[]) {
  290. Object [] msgs = (Object[]) msg;
  291. for (int i = 0; i < msgs.length; i++) {
  292. addMessageComponents(container, cons, msgs[i], maxll, false);
  293. }
  294. } else if (msg instanceof Icon) {
  295. JLabel label = new JLabel( (Icon)msg, SwingConstants.CENTER );
  296. label.setForeground(UIManager.getColor("OptionPane.messageForeground"));
  297. addMessageComponents(container, cons, label, maxll, true);
  298. } else {
  299. String s = msg.toString();
  300. int len = s.length();
  301. if (len <= 0) {
  302. return;
  303. }
  304. int nl = s.indexOf('\n');
  305. if (nl >= 0) {
  306. // break up newlines
  307. if (nl == 0) {
  308. addMessageComponents(container, cons, new Component() {
  309. public Dimension getPreferredSize() {
  310. Font f = getFont();
  311. if (f != null) {
  312. return new Dimension(1, f.getSize() + 2);
  313. }
  314. return new Dimension(0, 0);
  315. }
  316. }, maxll, true);
  317. } else {
  318. addMessageComponents(container, cons, s.substring(0, nl),
  319. maxll, false);
  320. }
  321. addMessageComponents(container, cons, s.substring(nl + 1), maxll,
  322. false);
  323. } else if (len > maxll) {
  324. Container c = Box.createVerticalBox();
  325. burstStringInto(c, s, maxll);
  326. addMessageComponents(container, cons, c, maxll, true );
  327. } else {
  328. JLabel label = new JLabel( s, JLabel.LEFT );
  329. label.setForeground(UIManager.getColor("OptionPane.messageForeground"));
  330. addMessageComponents(container, cons, label, maxll, true);
  331. }
  332. }
  333. }
  334. /**
  335. * Returns the message to display from the JOptionPane the receiver is
  336. * providing the look and feel for.
  337. */
  338. protected Object getMessage() {
  339. inputComponent = null;
  340. if (optionPane != null) {
  341. if (optionPane.getWantsInput()) {
  342. /* Create a user comopnent to capture the input. If the
  343. selectionValues are non null the component and there
  344. are < 20 values it'll be a combobox, if non null and
  345. >= 20, it'll be a list, otherwise it'll be a textfield. */
  346. Object message = optionPane.getMessage();
  347. Object[] sValues = optionPane.getSelectionValues();
  348. Object inputValue = optionPane
  349. .getInitialSelectionValue();
  350. JComponent toAdd;
  351. if (sValues != null) {
  352. if (sValues.length < 20) {
  353. JComboBox cBox = new JComboBox();
  354. for(int counter = 0, maxCounter = sValues.length;
  355. counter < maxCounter; counter++) {
  356. cBox.addItem(sValues[counter]);
  357. }
  358. if (inputValue != null) {
  359. cBox.setSelectedItem(inputValue);
  360. }
  361. inputComponent = cBox;
  362. toAdd = cBox;
  363. } else {
  364. JList list = new JList(sValues);
  365. JScrollPane sp = new JScrollPane(list);
  366. list.setVisibleRowCount(10);
  367. if(inputValue != null)
  368. list.setSelectedValue(inputValue, true);
  369. list.addMouseListener(new ListSelectionListener());
  370. toAdd = sp;
  371. inputComponent = list;
  372. }
  373. } else {
  374. JTextField tf = new JTextField(20);
  375. if (inputValue != null) {
  376. String inputString = inputValue.toString();
  377. tf.setText(inputString);
  378. tf.setSelectionStart(0);
  379. tf.setSelectionEnd(inputString.length());
  380. }
  381. tf.addActionListener(new TextFieldActionListener());
  382. toAdd = inputComponent = tf;
  383. }
  384. Object[] newMessage;
  385. if (message == null) {
  386. newMessage = new Object[1];
  387. newMessage[0] = toAdd;
  388. } else {
  389. newMessage = new Object[2];
  390. newMessage[0] = message;
  391. newMessage[1] = toAdd;
  392. }
  393. return newMessage;
  394. }
  395. return optionPane.getMessage();
  396. }
  397. return null;
  398. }
  399. /**
  400. * Creates and adds a JLabel representing the icon returned from
  401. * <code>getIcon</code> to <code>top</code>. This is messaged from
  402. * <code>createMessageArea</code>
  403. */
  404. protected void addIcon(Container top) {
  405. /* Create the icon. */
  406. Icon sideIcon = getIcon();
  407. if (sideIcon != null) {
  408. JLabel iconLabel = new JLabel(sideIcon);
  409. iconLabel.setVerticalAlignment(SwingConstants.TOP);
  410. top.add(iconLabel, BorderLayout.WEST);
  411. }
  412. }
  413. /**
  414. * Returns the icon from the JOptionPane the reciever is providing
  415. * the look and feel for, or the default icon as returned from
  416. * getDefaultIcon.
  417. */
  418. protected Icon getIcon() {
  419. Icon mIcon = (optionPane == null ? null : optionPane.getIcon());
  420. if(mIcon == null && optionPane != null)
  421. mIcon = getIconForType(optionPane.getMessageType());
  422. return mIcon;
  423. }
  424. /**
  425. * Returns the icon to use for the passed in type.
  426. */
  427. protected Icon getIconForType(int messageType) {
  428. if(messageType < 0 || messageType > 3)
  429. return null;
  430. switch(messageType) {
  431. case 0:
  432. return UIManager.getIcon("OptionPane.errorIcon");
  433. case 1:
  434. return UIManager.getIcon("OptionPane.informationIcon");
  435. case 2:
  436. return UIManager.getIcon("OptionPane.warningIcon");
  437. case 3:
  438. return UIManager.getIcon("OptionPane.questionIcon");
  439. }
  440. return null;
  441. }
  442. /**
  443. * Returns the maximum number of characters to place on a line.
  444. */
  445. protected int getMaxCharactersPerLineCount() {
  446. return optionPane.getMaxCharactersPerLineCount();
  447. }
  448. /**
  449. * Recursively creates new JLabel instances to represent <code>d</code>.
  450. * Each JLabel instance is added to <code>c</code>.
  451. */
  452. protected void burstStringInto(Container c, String d, int maxll) {
  453. // Primitive line wrapping
  454. int len = d.length();
  455. if (len <= 0)
  456. return;
  457. if (len > maxll) {
  458. int p = d.lastIndexOf(' ', maxll);
  459. if (p <= 0)
  460. p = d.indexOf(' ', maxll);
  461. if (p > 0 && p < len) {
  462. burstStringInto(c, d.substring(0, p), maxll);
  463. burstStringInto(c, d.substring(p + 1), maxll);
  464. return;
  465. }
  466. }
  467. JLabel label = new JLabel(d, JLabel.LEFT);
  468. label.setForeground(UIManager.getColor("OptionPane.messageForeground"));
  469. c.add(label);
  470. }
  471. protected Container createSeparator() {
  472. return null;
  473. }
  474. /**
  475. * Creates and returns a Container containin the buttons. The buttons
  476. * are created by calling <code>getButtons</code>.
  477. */
  478. protected Container createButtonArea() {
  479. JPanel bottom = new JPanel();
  480. bottom.setBorder(UIManager.getBorder("OptionPane.buttonAreaBorder"));
  481. bottom.setLayout(new ButtonAreaLayout(true, 6));
  482. addButtonComponents(bottom, getButtons(), getInitialValueIndex());
  483. return bottom;
  484. }
  485. /**
  486. * Creates the appropriate object to represent each of the objects in
  487. * <code>buttons</code> and adds it to <code>container</code>. This
  488. * differs from addMessageComponents in that it will recurse on
  489. * <code>buttons</code> and that if button is not a Component
  490. * it will create an instance of JButton.
  491. */
  492. protected void addButtonComponents(Container container, Object[] buttons,
  493. int initialIndex) {
  494. if (buttons != null && buttons.length > 0) {
  495. boolean sizeButtonsToSame = getSizeButtonsToSameWidth();
  496. boolean createdAll = true;
  497. int numButtons = buttons.length;
  498. JButton[] createdButtons = null;
  499. int maxWidth = 0;
  500. if (sizeButtonsToSame) {
  501. createdButtons = new JButton[numButtons];
  502. }
  503. for(int counter = 0; counter < numButtons; counter++) {
  504. Object button = buttons[counter];
  505. Component newComponent;
  506. if (button instanceof Component) {
  507. createdAll = false;
  508. newComponent = (Component)button;
  509. container.add(newComponent);
  510. hasCustomComponents = true;
  511. } else {
  512. JButton aButton;
  513. if (button instanceof Icon)
  514. aButton = new JButton((Icon)button);
  515. else
  516. aButton = new JButton(button.toString());
  517. container.add(aButton);
  518. ActionListener buttonListener = createButtonActionListener(counter);
  519. if (buttonListener != null) {
  520. aButton.addActionListener(buttonListener);
  521. }
  522. newComponent = aButton;
  523. }
  524. if (sizeButtonsToSame && createdAll &&
  525. (newComponent instanceof JButton)) {
  526. createdButtons[counter] = (JButton)newComponent;
  527. maxWidth = Math.max(maxWidth,
  528. newComponent.getMinimumSize().width);
  529. }
  530. if (counter == initialIndex) {
  531. initialFocusComponent = newComponent;
  532. if (initialFocusComponent instanceof JButton) {
  533. JButton defaultB = (JButton)initialFocusComponent;
  534. defaultB.addAncestorListener(new AncestorListener() {
  535. public void ancestorAdded(AncestorEvent e) {
  536. JButton defaultButton = (JButton)e.getComponent();
  537. JRootPane root = SwingUtilities.getRootPane(defaultButton);
  538. if (root != null) {
  539. root.setDefaultButton(defaultButton);
  540. }
  541. }
  542. public void ancestorRemoved(AncestorEvent event) {}
  543. public void ancestorMoved(AncestorEvent event) {}
  544. });
  545. }
  546. }
  547. }
  548. ((ButtonAreaLayout)container.getLayout()).
  549. setSyncAllWidths((sizeButtonsToSame && createdAll));
  550. /* Set the padding, windows seems to use 8 if <= 2 components,
  551. otherwise 4 is used. It may actually just be the size of the
  552. buttons is always the same, not sure. */
  553. if (sizeButtonsToSame && createdAll) {
  554. JButton aButton;
  555. int padSize;
  556. padSize = (numButtons <= 2? 8 : 4);
  557. for(int counter = 0; counter < numButtons; counter++) {
  558. aButton = createdButtons[counter];
  559. aButton.setMargin(new Insets(2, padSize, 2, padSize));
  560. }
  561. }
  562. }
  563. }
  564. protected ActionListener createButtonActionListener(int buttonIndex) {
  565. return new ButtonActionListener(buttonIndex);
  566. }
  567. /**
  568. * Returns the buttons to display from the JOptionPane the receiver is
  569. * providing the look and feel for. If the JOptionPane has options
  570. * set, they will be provided, otherwise if the optionType is
  571. * YES_NO_OPTION, yesNoOptions is returned, if the type is
  572. * YES_NO_CANCEL_OPTION yesNoCancelOptions is returned, otherwise
  573. * defaultButtons are returned.
  574. */
  575. protected Object[] getButtons() {
  576. if (optionPane != null) {
  577. Object[] suppliedOptions = optionPane.getOptions();
  578. if (suppliedOptions == null) {
  579. Object[] defaultOptions;
  580. int type = optionPane.getOptionType();
  581. if (type == JOptionPane.YES_NO_OPTION) {
  582. defaultOptions = new String[2];
  583. defaultOptions[0] = UIManager.get("OptionPane.yesButtonText");
  584. defaultOptions[1] = UIManager.get("OptionPane.noButtonText");
  585. } else if (type == JOptionPane.YES_NO_CANCEL_OPTION) {
  586. defaultOptions = new String[3];
  587. defaultOptions[0] = UIManager.get("OptionPane.yesButtonText");
  588. defaultOptions[1] = UIManager.get("OptionPane.noButtonText");
  589. defaultOptions[2] = UIManager.get("OptionPane.cancelButtonText");
  590. } else if (type == JOptionPane.OK_CANCEL_OPTION) {
  591. defaultOptions = new String[2];
  592. defaultOptions[0] = UIManager.get("OptionPane.okButtonText");
  593. defaultOptions[1] = UIManager.get("OptionPane.cancelButtonText");
  594. } else {
  595. defaultOptions = new String[1];
  596. defaultOptions[0] = UIManager.get("OptionPane.okButtonText");
  597. }
  598. return defaultOptions;
  599. }
  600. return suppliedOptions;
  601. }
  602. return null;
  603. }
  604. /**
  605. * Returns true, basic L&F wants all the buttons to have the same
  606. * width.
  607. */
  608. protected boolean getSizeButtonsToSameWidth() {
  609. return true;
  610. }
  611. /**
  612. * Returns the initial index into the buttons to select. The index
  613. * is calculated from the initial value from the JOptionPane and
  614. * options of the JOptionPane or 0.
  615. */
  616. protected int getInitialValueIndex() {
  617. if (optionPane != null) {
  618. Object iv = optionPane.getInitialValue();
  619. Object[] options = optionPane.getOptions();
  620. if(options == null) {
  621. return 0;
  622. }
  623. else if(iv != null) {
  624. for(int counter = options.length - 1; counter >= 0; counter--){
  625. if(options[counter].equals(iv))
  626. return counter;
  627. }
  628. }
  629. }
  630. return -1;
  631. }
  632. /**
  633. * Sets the input value in the option pane the receiver is providing
  634. * the look and feel for based on the value in the inputComponent.
  635. */
  636. protected void resetInputValue() {
  637. if(inputComponent != null && (inputComponent instanceof JTextField)) {
  638. optionPane.setInputValue(((JTextField)inputComponent).getText());
  639. } else if(inputComponent != null &&
  640. (inputComponent instanceof JComboBox)) {
  641. optionPane.setInputValue(((JComboBox)inputComponent)
  642. .getSelectedItem());
  643. } else if(inputComponent != null) {
  644. optionPane.setInputValue(((JList)inputComponent)
  645. .getSelectedValue());
  646. }
  647. }
  648. /**
  649. * If inputComponent is non-null, the focus is requested on that,
  650. * otherwise request focus on the default value
  651. */
  652. public void selectInitialValue(JOptionPane op) {
  653. if (inputComponent != null)
  654. inputComponent.requestFocus();
  655. else {
  656. if (initialFocusComponent != null)
  657. initialFocusComponent.requestFocus();
  658. if (initialFocusComponent instanceof JButton) {
  659. JRootPane root = SwingUtilities.getRootPane(initialFocusComponent);
  660. if (root != null) {
  661. root.setDefaultButton((JButton)initialFocusComponent);
  662. }
  663. }
  664. }
  665. }
  666. /**
  667. * Returns true if in the last call to validateComponent the message
  668. * or buttons contained a subclass of Component.
  669. */
  670. public boolean containsCustomComponents(JOptionPane op) {
  671. return hasCustomComponents;
  672. }
  673. /**
  674. * ButtonAreaLayout acts similiar to FlowLayout. It lays out all
  675. * components from left to right. If syncAllWidths is true, the widths
  676. * of each component will be set to the largest preferred size width.
  677. *
  678. * This inner class is marked "public" due to a compiler bug.
  679. * This class should be treated as a "protected" inner class.
  680. * Instantiate it only within subclasses of BasicOptionPaneUI.
  681. */
  682. public static class ButtonAreaLayout implements LayoutManager {
  683. protected boolean syncAllWidths;
  684. protected int padding;
  685. /** If true, children are lumped together in parent. */
  686. protected boolean centersChildren;
  687. public ButtonAreaLayout(boolean syncAllWidths, int padding) {
  688. this.syncAllWidths = syncAllWidths;
  689. this.padding = padding;
  690. centersChildren = true;
  691. }
  692. public void setSyncAllWidths(boolean newValue) {
  693. syncAllWidths = newValue;
  694. }
  695. public boolean getSyncAllWidths() {
  696. return syncAllWidths;
  697. }
  698. public void setPadding(int newPadding) {
  699. this.padding = newPadding;
  700. }
  701. public int getPadding() {
  702. return padding;
  703. }
  704. public void setCentersChildren(boolean newValue) {
  705. centersChildren = newValue;
  706. }
  707. public boolean getCentersChildren() {
  708. return centersChildren;
  709. }
  710. public void addLayoutComponent(String string, Component comp) {
  711. }
  712. public void layoutContainer(Container container) {
  713. Component[] children = container.getComponents();
  714. if(children != null && children.length > 0) {
  715. int numChildren = children.length;
  716. Dimension[] sizes = new Dimension[numChildren];
  717. int counter;
  718. int yLocation = container.getInsets().top;
  719. if(syncAllWidths) {
  720. int maxWidth = 0;
  721. for(counter = 0; counter < numChildren; counter++) {
  722. sizes[counter] = children[counter].getPreferredSize();
  723. maxWidth = Math.max(maxWidth, sizes[counter].width);
  724. }
  725. int xLocation;
  726. int xOffset;
  727. if(getCentersChildren()) {
  728. xLocation = (container.getSize().width -
  729. (maxWidth * numChildren +
  730. (numChildren - 1) * padding)) / 2;
  731. xOffset = padding + maxWidth;
  732. }
  733. else {
  734. if(numChildren > 1) {
  735. xLocation = 0;
  736. xOffset = (container.getSize().width -
  737. (maxWidth * numChildren)) /
  738. (numChildren - 1) + maxWidth;
  739. }
  740. else {
  741. xLocation = (container.getSize().width -
  742. maxWidth) / 2;
  743. xOffset = 0;
  744. }
  745. }
  746. for(counter = 0; counter < numChildren; counter++) {
  747. children[counter].setBounds(xLocation, yLocation,
  748. maxWidth,
  749. sizes[counter].height);
  750. xLocation += xOffset;
  751. }
  752. }
  753. else {
  754. int totalWidth = 0;
  755. for(counter = 0; counter < numChildren; counter++) {
  756. sizes[counter] = children[counter].getPreferredSize();
  757. totalWidth += sizes[counter].width;
  758. }
  759. totalWidth += ((numChildren - 1) * padding);
  760. boolean cc = getCentersChildren();
  761. int xOffset;
  762. int xLocation;
  763. if(cc) {
  764. xLocation = (container.getSize().width -
  765. totalWidth) / 2;
  766. xOffset = padding;
  767. }
  768. else {
  769. if(numChildren > 1) {
  770. xOffset = (container.getSize().width -
  771. totalWidth) / (numChildren - 1);
  772. xLocation = 0;
  773. }
  774. else {
  775. xLocation = (container.getSize().width -
  776. totalWidth) / 2;
  777. xOffset = 0;
  778. }
  779. }
  780. for(counter = 0; counter < numChildren; counter++) {
  781. children[counter].setBounds(xLocation, yLocation,
  782. sizes[counter].width, sizes[counter].height);
  783. xLocation += xOffset + sizes[counter].width;
  784. }
  785. }
  786. }
  787. }
  788. public Dimension minimumLayoutSize(Container c) {
  789. if(c != null) {
  790. Component[] children = c.getComponents();
  791. if(children != null && children.length > 0) {
  792. Dimension aSize;
  793. int numChildren = children.length;
  794. int height = 0;
  795. Insets cInsets = c.getInsets();
  796. int extraHeight = cInsets.top + cInsets.bottom;
  797. if (syncAllWidths) {
  798. int maxWidth = 0;
  799. for(int counter = 0; counter < numChildren; counter++){
  800. aSize = children[counter].getPreferredSize();
  801. height = Math.max(height, aSize.height);
  802. maxWidth = Math.max(maxWidth, aSize.width);
  803. }
  804. return new Dimension(maxWidth * numChildren +
  805. (numChildren - 1) * padding,
  806. extraHeight + height);
  807. }
  808. else {
  809. int totalWidth = 0;
  810. for(int counter = 0; counter < numChildren; counter++){
  811. aSize = children[counter].getPreferredSize();
  812. height = Math.max(height, aSize.height);
  813. totalWidth += aSize.width;
  814. }
  815. totalWidth += ((numChildren - 1) * padding);
  816. return new Dimension(totalWidth, extraHeight + height);
  817. }
  818. }
  819. }
  820. return new Dimension(0, 0);
  821. }
  822. public Dimension preferredLayoutSize(Container c) {
  823. return minimumLayoutSize(c);
  824. }
  825. public void removeLayoutComponent(Component c) { }
  826. }
  827. /**
  828. * This inner class is marked "public" due to a compiler bug.
  829. * This class should be treated as a "protected" inner class.
  830. * Instantiate it only within subclasses of BasicOptionPaneUI.
  831. */
  832. public class PropertyChangeHandler implements PropertyChangeListener {
  833. /**
  834. * If the source of the PropertyChangeEvent <code>e</code> equals the
  835. * optionPane and is one of the ICON_PROPERTY, MESSAGE_PROPERTY,
  836. * OPTIONS_PROPERTY or INITIAL_VALUE_PROPERTY,
  837. * validateComponent is invoked.
  838. */
  839. public void propertyChange(PropertyChangeEvent e) {
  840. if(e.getSource() == optionPane) {
  841. String changeName = e.getPropertyName();
  842. if(changeName.equals(JOptionPane.OPTIONS_PROPERTY) ||
  843. changeName.equals(JOptionPane.INITIAL_VALUE_PROPERTY) ||
  844. changeName.equals(JOptionPane.ICON_PROPERTY) ||
  845. changeName.equals(JOptionPane.MESSAGE_TYPE_PROPERTY) ||
  846. changeName.equals(JOptionPane.OPTION_TYPE_PROPERTY) ||
  847. changeName.equals(JOptionPane.MESSAGE_PROPERTY) ||
  848. changeName.equals(JOptionPane.SELECTION_VALUES_PROPERTY) ||
  849. changeName.equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY) ||
  850. changeName.equals(JOptionPane.WANTS_INPUT_PROPERTY)) {
  851. uninstallComponents();
  852. installComponents();
  853. optionPane.validate();
  854. }
  855. }
  856. }
  857. }
  858. /**
  859. * This inner class is marked "public" due to a compiler bug.
  860. * This class should be treated as a "protected" inner class.
  861. * Instantiate it only within subclasses of BasicOptionPaneUI.
  862. */
  863. public class ButtonActionListener implements ActionListener {
  864. protected int buttonIndex;
  865. public ButtonActionListener(int buttonIndex) {
  866. this.buttonIndex = buttonIndex;
  867. }
  868. public void actionPerformed(ActionEvent e) {
  869. if (optionPane != null) {
  870. int messageType = optionPane.getOptionType();
  871. if (inputComponent != null &&
  872. (messageType == JOptionPane.YES_NO_OPTION ||
  873. messageType == JOptionPane.YES_NO_CANCEL_OPTION ||
  874. messageType == JOptionPane.OK_CANCEL_OPTION) &&
  875. buttonIndex == 0) {
  876. resetInputValue();
  877. }
  878. Object[] options = optionPane.getOptions();
  879. if (options == null) {
  880. if (messageType == JOptionPane.OK_CANCEL_OPTION &&
  881. buttonIndex == 1) {
  882. optionPane.setValue(new Integer(2));
  883. } else {
  884. optionPane.setValue(new Integer(buttonIndex));
  885. }
  886. } else {
  887. optionPane.setValue(options[buttonIndex]);
  888. }
  889. }
  890. }
  891. }
  892. //
  893. // Classed used when optionPane.getWantsInput returns true.
  894. //
  895. /**
  896. * Listener when a JList is created to handle input from the user.
  897. */
  898. private class ListSelectionListener extends MouseAdapter
  899. {
  900. public void mousePressed(MouseEvent e) {
  901. if (e.getClickCount() == 2) {
  902. JList list = (JList)e.getSource();
  903. int index = list.locationToIndex(e.getPoint());
  904. optionPane.setInputValue(list.getModel().getElementAt(index));
  905. }
  906. }
  907. }
  908. /**
  909. * Listener when a JTextField is created to handle input from the user.
  910. */
  911. private class TextFieldActionListener implements ActionListener
  912. {
  913. public void actionPerformed(ActionEvent e) {
  914. optionPane.setInputValue(((JTextField)e.getSource()).getText());
  915. }
  916. }
  917. // REMIND(aim,7/29/98): These actions should be broken
  918. // out into protected inner classes in the next release where
  919. // API changes are allowed
  920. /**
  921. * Registered in the ActionMap. Sets the value of the option pane
  922. * to <code>JOptionPane.CLOSED_OPTION</code>.
  923. */
  924. private static class CloseAction extends AbstractAction {
  925. public void actionPerformed(ActionEvent e) {
  926. JOptionPane optionPane = (JOptionPane)e.getSource();
  927. optionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));
  928. }
  929. }
  930. }