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