Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)
Frames | No Frames

Source for javax.swing.plaf.basic.BasicOptionPaneUI

 1:  /* BasicOptionPaneUI.java --
 2:  Copyright (C) 2004, 2005 Free Software Foundation, Inc.
 3: 
 4: This file is part of GNU Classpath.
 5: 
 6: GNU Classpath is free software; you can redistribute it and/or modify
 7: it under the terms of the GNU General Public License as published by
 8: the Free Software Foundation; either version 2, or (at your option)
 9: any later version.
 10: 
 11: GNU Classpath is distributed in the hope that it will be useful, but
 12: WITHOUT ANY WARRANTY; without even the implied warranty of
 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 14: General Public License for more details.
 15: 
 16: You should have received a copy of the GNU General Public License
 17: along with GNU Classpath; see the file COPYING. If not, write to the
 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 19: 02110-1301 USA.
 20: 
 21: Linking this library statically or dynamically with other modules is
 22: making a combined work based on this library. Thus, the terms and
 23: conditions of the GNU General Public License cover the whole
 24: combination.
 25: 
 26: As a special exception, the copyright holders of this library give you
 27: permission to link this library with independent modules to produce an
 28: executable, regardless of the license terms of these independent
 29: modules, and to copy and distribute the resulting executable under
 30: terms of your choice, provided that you also meet, for each linked
 31: independent module, the terms and conditions of the license of that
 32: module. An independent module is a module which is not derived from
 33: or based on this library. If you modify this library, you may extend
 34: this exception to your version of the library, but you are not
 35: obligated to do so. If you do not wish to do so, delete this
 36: exception statement from your version. */
 37: 
 38: 
 39:  package javax.swing.plaf.basic;
 40: 
 41:  import java.awt.BorderLayout;
 42:  import java.awt.Color;
 43:  import java.awt.Component;
 44:  import java.awt.Container;
 45:  import java.awt.Dimension;
 46:  import java.awt.Font;
 47:  import java.awt.Graphics;
 48:  import java.awt.GridBagConstraints;
 49:  import java.awt.GridBagLayout;
 50:  import java.awt.Insets;
 51:  import java.awt.LayoutManager;
 52:  import java.awt.Polygon;
 53:  import java.awt.Window;
 54:  import java.awt.event.ActionEvent;
 55:  import java.awt.event.ActionListener;
 56:  import java.beans.PropertyChangeEvent;
 57:  import java.beans.PropertyChangeListener;
 58:  import java.beans.PropertyVetoException;
 59: 
 60:  import javax.swing.AbstractAction;
 61:  import javax.swing.Action;
 62:  import javax.swing.ActionMap;
 63:  import javax.swing.BorderFactory;
 64:  import javax.swing.Box;
 65:  import javax.swing.BoxLayout;
 66:  import javax.swing.Icon;
 67:  import javax.swing.InputMap;
 68:  import javax.swing.JButton;
 69:  import javax.swing.JComboBox;
 70:  import javax.swing.JComponent;
 71:  import javax.swing.JDialog;
 72:  import javax.swing.JInternalFrame;
 73:  import javax.swing.JLabel;
 74:  import javax.swing.JList;
 75:  import javax.swing.JOptionPane;
 76:  import javax.swing.JPanel;
 77:  import javax.swing.JTextField;
 78:  import javax.swing.LookAndFeel;
 79:  import javax.swing.SwingUtilities;
 80:  import javax.swing.UIManager;
 81:  import javax.swing.border.Border;
 82:  import javax.swing.plaf.ActionMapUIResource;
 83:  import javax.swing.plaf.ComponentUI;
 84:  import javax.swing.plaf.OptionPaneUI;
 85: 
 86:  /**
 87:  * This class is the UI delegate for JOptionPane in the Basic Look and Feel.
 88:  */
 89:  public class BasicOptionPaneUI extends OptionPaneUI
 90: {
 91:  /**
 92:  * Implements the "close" keyboard action.
 93:  */
 94:  static class OptionPaneCloseAction
 95:  extends AbstractAction
 96:  {
 97: 
 98:  public void actionPerformed(ActionEvent event)
 99:  {
 100:  JOptionPane op = (JOptionPane) event.getSource();
 101:  op.setValue(new Integer(JOptionPane.CLOSED_OPTION));
 102:  }
 103:  
 104:  }
 105: 
 106:  /**
 107:  * This is a helper class that listens to the buttons located at the bottom
 108:  * of the JOptionPane.
 109:  *
 110:  * @specnote Apparently this class was intended to be protected,
 111:  * but was made public by a compiler bug and is now
 112:  * public for compatibility.
 113:  */
 114:  public class ButtonActionListener implements ActionListener
 115:  {
 116:  /** The index of the option this button represents. */
 117:  protected int buttonIndex;
 118: 
 119:  /**
 120:  * Creates a new ButtonActionListener object with the given buttonIndex.
 121:  *
 122:  * @param buttonIndex The index of the option this button represents.
 123:  */
 124:  public ButtonActionListener(int buttonIndex)
 125:  {
 126:  this.buttonIndex = buttonIndex;
 127:  }
 128: 
 129:  /**
 130:  * This method is called when one of the option buttons are pressed.
 131:  *
 132:  * @param e The ActionEvent.
 133:  */
 134:  public void actionPerformed(ActionEvent e)
 135:  {
 136:  Object value = new Integer(JOptionPane.CLOSED_OPTION);
 137:  Object[] options = optionPane.getOptions();
 138:  if (options != null)
 139:  value = new Integer(buttonIndex);
 140:  else
 141:  {
 142:  String text = ((JButton) e.getSource()).getText();
 143:  if (text.equals(OK_STRING))
 144:  value = new Integer(JOptionPane.OK_OPTION);
 145:  if (text.equals(CANCEL_STRING))
 146:  value = new Integer(JOptionPane.CANCEL_OPTION);
 147:  if (text.equals(YES_STRING))
 148:  value = new Integer(JOptionPane.YES_OPTION);
 149:  if (text.equals(NO_STRING))
 150:  value = new Integer(JOptionPane.NO_OPTION);
 151:  }
 152:  optionPane.setValue(value);
 153:  resetInputValue();
 154: 
 155:  Window owner = SwingUtilities.windowForComponent(optionPane);
 156: 
 157:  if (owner instanceof JDialog)
 158:  ((JDialog) owner).dispose();
 159: 
 160:  //else we probably have some kind of internal frame.
 161:  JInternalFrame inf = (JInternalFrame) SwingUtilities.getAncestorOfClass(
 162:  JInternalFrame.class, optionPane);
 163:  if (inf != null)
 164:  {
 165:  try
 166:  {
 167:  inf.setClosed(true);
 168:  }
 169:  catch (PropertyVetoException pve)
 170:  {
 171:  // We do nothing if attempt has been vetoed.
 172:  }
 173:  }
 174:  }
 175:  }
 176: 
 177:  /**
 178:  * This helper layout manager is responsible for the layout of the button
 179:  * area. The button area is the panel that holds the buttons which
 180:  * represent the options.
 181:  *
 182:  * @specnote Apparently this class was intended to be protected,
 183:  * but was made public by a compiler bug and is now
 184:  * public for compatibility.
 185:  */
 186:  public static class ButtonAreaLayout implements LayoutManager
 187:  {
 188:  /** Whether this layout will center the buttons. */
 189:  protected boolean centersChildren = true;
 190: 
 191:  /** The space between the buttons. */
 192:  protected int padding;
 193: 
 194:  /** Whether the buttons will share the same widths. */
 195:  protected boolean syncAllWidths;
 196: 
 197:  /** The width of the widest button. */
 198:  private transient int widthOfWidestButton;
 199: 
 200:  /** The height of the tallest button. */
 201:  private transient int tallestButton;
 202: 
 203:  /**
 204:  * Creates a new ButtonAreaLayout object with the given sync widths
 205:  * property and padding.
 206:  *
 207:  * @param syncAllWidths Whether the buttons will share the same widths.
 208:  * @param padding The padding between the buttons.
 209:  */
 210:  public ButtonAreaLayout(boolean syncAllWidths, int padding)
 211:  {
 212:  this.syncAllWidths = syncAllWidths;
 213:  this.padding = padding;
 214:  }
 215: 
 216:  /**
 217:  * This method is called when a component is added to the container.
 218:  *
 219:  * @param string The constraints string.
 220:  * @param comp The component added.
 221:  */
 222:  public void addLayoutComponent(String string, Component comp)
 223:  {
 224:  // Do nothing.
 225:  }
 226: 
 227:  /**
 228:  * This method returns whether the children will be centered.
 229:  *
 230:  * @return Whether the children will be centered.
 231:  */
 232:  public boolean getCentersChildren()
 233:  {
 234:  return centersChildren;
 235:  }
 236: 
 237:  /**
 238:  * This method returns the amount of space between components.
 239:  *
 240:  * @return The amount of space between components.
 241:  */
 242:  public int getPadding()
 243:  {
 244:  return padding;
 245:  }
 246: 
 247:  /**
 248:  * This method returns whether all components will share widths (set to
 249:  * largest width).
 250:  *
 251:  * @return Whether all components will share widths.
 252:  */
 253:  public boolean getSyncAllWidths()
 254:  {
 255:  return syncAllWidths;
 256:  }
 257: 
 258:  /**
 259:  * This method lays out the given container.
 260:  *
 261:  * @param container The container to lay out.
 262:  */
 263:  public void layoutContainer(Container container)
 264:  {
 265:  Component[] buttonList = container.getComponents();
 266:  int x = container.getInsets().left;
 267:  if (getCentersChildren())
 268:  x += (int) ((double) (container.getSize().width) / 2
 269:  - (double) (buttonRowLength(container)) / 2);
 270:  for (int i = 0; i < buttonList.length; i++)
 271:  {
 272:  Dimension dims = buttonList[i].getPreferredSize();
 273:  if (syncAllWidths)
 274:  {
 275:  buttonList[i].setBounds(x, 0, widthOfWidestButton, dims.height);
 276:  x += widthOfWidestButton + getPadding();
 277:  }
 278:  else
 279:  {
 280:  buttonList[i].setBounds(x, 0, dims.width, dims.height);
 281:  x += dims.width + getPadding();
 282:  }
 283:  }
 284:  }
 285: 
 286:  /**
 287:  * This method returns the width of the given container taking into
 288:  * consideration the padding and syncAllWidths.
 289:  *
 290:  * @param c The container to calculate width for.
 291:  *
 292:  * @return The width of the given container.
 293:  */
 294:  private int buttonRowLength(Container c)
 295:  {
 296:  Component[] buttonList = c.getComponents();
 297: 
 298:  int buttonLength = 0;
 299:  int widest = 0;
 300:  int tallest = 0;
 301: 
 302:  for (int i = 0; i < buttonList.length; i++)
 303:  {
 304:  Dimension dims = buttonList[i].getPreferredSize();
 305:  buttonLength += dims.width + getPadding();
 306:  widest = Math.max(widest, dims.width);
 307:  tallest = Math.max(tallest, dims.height);
 308:  }
 309: 
 310:  widthOfWidestButton = widest;
 311:  tallestButton = tallest;
 312: 
 313:  int width;
 314:  if (getSyncAllWidths())
 315:  width = widest * buttonList.length
 316:  + getPadding() * (buttonList.length - 1);
 317:  else
 318:  width = buttonLength;
 319: 
 320:  Insets insets = c.getInsets();
 321:  width += insets.left + insets.right;
 322: 
 323:  return width;
 324:  }
 325: 
 326:  /**
 327:  * This method returns the minimum layout size for the given container.
 328:  *
 329:  * @param c The container to measure.
 330:  *
 331:  * @return The minimum layout size.
 332:  */
 333:  public Dimension minimumLayoutSize(Container c)
 334:  {
 335:  return preferredLayoutSize(c);
 336:  }
 337: 
 338:  /**
 339:  * This method returns the preferred size of the given container.
 340:  *
 341:  * @param c The container to measure.
 342:  *
 343:  * @return The preferred size.
 344:  */
 345:  public Dimension preferredLayoutSize(Container c)
 346:  {
 347:  int w = buttonRowLength(c);
 348: 
 349:  return new Dimension(w, tallestButton);
 350:  }
 351: 
 352:  /**
 353:  * This method removes the given component from the layout manager's
 354:  * knowledge.
 355:  *
 356:  * @param c The component to remove.
 357:  */
 358:  public void removeLayoutComponent(Component c)
 359:  {
 360:  // Do nothing.
 361:  }
 362: 
 363:  /**
 364:  * This method sets whether the children will be centered.
 365:  *
 366:  * @param newValue Whether the children will be centered.
 367:  */
 368:  public void setCentersChildren(boolean newValue)
 369:  {
 370:  centersChildren = newValue;
 371:  }
 372: 
 373:  /**
 374:  * This method sets the amount of space between each component.
 375:  *
 376:  * @param newPadding The padding between components.
 377:  */
 378:  public void setPadding(int newPadding)
 379:  {
 380:  padding = newPadding;
 381:  }
 382: 
 383:  /**
 384:  * This method sets whether the widths will be synced.
 385:  *
 386:  * @param newValue Whether the widths will be synced.
 387:  */
 388:  public void setSyncAllWidths(boolean newValue)
 389:  {
 390:  syncAllWidths = newValue;
 391:  }
 392:  }
 393: 
 394:  /**
 395:  * This helper class handles property change events from the JOptionPane.
 396:  *
 397:  * @specnote Apparently this class was intended to be protected,
 398:  * but was made public by a compiler bug and is now
 399:  * public for compatibility.
 400:  */
 401:  public class PropertyChangeHandler implements PropertyChangeListener
 402:  {
 403:  /**
 404:  * This method is called when one of the properties of the JOptionPane
 405:  * changes.
 406:  *
 407:  * @param e The PropertyChangeEvent.
 408:  */
 409:  public void propertyChange(PropertyChangeEvent e)
 410:  {
 411:  String property = e.getPropertyName();
 412:  if (property.equals(JOptionPane.ICON_PROPERTY)
 413:  || property.equals(JOptionPane.INITIAL_SELECTION_VALUE_PROPERTY)
 414:  || property.equals(JOptionPane.INITIAL_VALUE_PROPERTY)
 415:  || property.equals(JOptionPane.MESSAGE_PROPERTY)
 416:  || property.equals(JOptionPane.MESSAGE_TYPE_PROPERTY)
 417:  || property.equals(JOptionPane.OPTION_TYPE_PROPERTY)
 418:  || property.equals(JOptionPane.OPTIONS_PROPERTY)
 419:  || property.equals(JOptionPane.WANTS_INPUT_PROPERTY))
 420:  {
 421:  uninstallComponents();
 422:  installComponents();
 423:  optionPane.validate();
 424:  }
 425:  }
 426:  }
 427: 
 428:  /**
 429:  * The minimum width for JOptionPanes.
 430:  */
 431:  public static final int MinimumWidth = 262;
 432: 
 433:  /**
 434:  * The minimum height for JOptionPanes.
 435:  */
 436:  public static final int MinimumHeight = 90;
 437: 
 438:  /** Whether the JOptionPane contains custom components. */
 439:  protected boolean hasCustomComponents;
 440: 
 441:  // The initialFocusComponent seems to always be set to a button (even if 
 442:  // I try to set initialSelectionValue). This is different from what the 
 443:  // javadocs state (which should switch this reference to the input component 
 444:  // if one is present since that is what's going to get focus). 
 445: 
 446:  /**
 447:  * The button that will receive focus based on initialValue when no input
 448:  * component is present. If an input component is present, then the input
 449:  * component will receive focus instead.
 450:  */
 451:  protected Component initialFocusComponent;
 452: 
 453:  /** The component that receives input when the JOptionPane needs it. */
 454:  protected JComponent inputComponent;
 455: 
 456:  /** The minimum dimensions of the JOptionPane. */
 457:  protected Dimension minimumSize;
 458: 
 459:  /** The propertyChangeListener for the JOptionPane. */
 460:  protected PropertyChangeListener propertyChangeListener;
 461: 
 462:  /** The JOptionPane this UI delegate is used for. */
 463:  protected JOptionPane optionPane;
 464: 
 465:  /** The size of the icons. */
 466:  private static final int ICON_SIZE = 36;
 467: 
 468:  /** The string used to describe OK buttons. */
 469:  private static final String OK_STRING = "OK";
 470: 
 471:  /** The string used to describe Yes buttons. */
 472:  private static final String YES_STRING = "Yes";
 473: 
 474:  /** The string used to describe No buttons. */
 475:  private static final String NO_STRING = "No";
 476: 
 477:  /** The string used to describe Cancel buttons. */
 478:  private static final String CANCEL_STRING = "Cancel";
 479: 
 480:  /** The container for the message area.
 481:  * This is package-private to avoid an accessor method. */
 482:  transient Container messageAreaContainer;
 483: 
 484:  /** The container for the buttons.
 485:  * This is package-private to avoid an accessor method. */
 486:  transient Container buttonContainer;
 487: 
 488:  /**
 489:  * A helper class that implements Icon. This is used temporarily until
 490:  * ImageIcons are fixed.
 491:  */
 492:  private static class MessageIcon implements Icon
 493:  {
 494:  /**
 495:  * This method returns the width of the icon.
 496:  *
 497:  * @return The width of the icon.
 498:  */
 499:  public int getIconWidth()
 500:  {
 501:  return ICON_SIZE;
 502:  }
 503: 
 504:  /**
 505:  * This method returns the height of the icon.
 506:  *
 507:  * @return The height of the icon.
 508:  */
 509:  public int getIconHeight()
 510:  {
 511:  return ICON_SIZE;
 512:  }
 513: 
 514:  /**
 515:  * This method paints the icon as a part of the given component using the
 516:  * given graphics and the given x and y position.
 517:  *
 518:  * @param c The component that owns this icon.
 519:  * @param g The Graphics object to paint with.
 520:  * @param x The x coordinate.
 521:  * @param y The y coordinate.
 522:  */
 523:  public void paintIcon(Component c, Graphics g, int x, int y)
 524:  {
 525:  // Nothing to do here.
 526:  }
 527:  }
 528: 
 529:  /** The icon displayed for ERROR_MESSAGE. */
 530:  private static MessageIcon errorIcon = new MessageIcon()
 531:  {
 532:  public void paintIcon(Component c, Graphics g, int x, int y)
 533:  {
 534:  Polygon oct = new Polygon(new int[] { 0, 0, 9, 27, 36, 36, 27, 9 },
 535:  new int[] { 9, 27, 36, 36, 27, 9, 0, 0 }, 8);
 536:  g.translate(x, y);
 537: 
 538:  Color saved = g.getColor();
 539:  g.setColor(Color.RED);
 540: 
 541:  g.fillPolygon(oct);
 542: 
 543:  g.setColor(Color.BLACK);
 544:  g.drawRect(13, 16, 10, 4);
 545: 
 546:  g.setColor(saved);
 547:  g.translate(-x, -y);
 548:  }
 549:  };
 550: 
 551:  /** The icon displayed for INFORMATION_MESSAGE. */
 552:  private static MessageIcon infoIcon = new MessageIcon()
 553:  {
 554:  public void paintIcon(Component c, Graphics g, int x, int y)
 555:  {
 556:  g.translate(x, y);
 557:  Color saved = g.getColor();
 558: 
 559:  // Should be purple.
 560:  g.setColor(Color.RED);
 561: 
 562:  g.fillOval(0, 0, ICON_SIZE, ICON_SIZE);
 563: 
 564:  g.setColor(Color.BLACK);
 565:  g.drawOval(16, 6, 4, 4);
 566: 
 567:  Polygon bottomI = new Polygon(new int[] { 15, 15, 13, 13, 23, 23, 21, 21 },
 568:  new int[] { 12, 28, 28, 30, 30, 28, 28, 12 },
 569:  8);
 570:  g.drawPolygon(bottomI);
 571: 
 572:  g.setColor(saved);
 573:  g.translate(-x, -y);
 574:  }
 575:  };
 576: 
 577:  /** The icon displayed for WARNING_MESSAGE. */
 578:  private static MessageIcon warningIcon = new MessageIcon()
 579:  {
 580:  public void paintIcon(Component c, Graphics g, int x, int y)
 581:  {
 582:  g.translate(x, y);
 583:  Color saved = g.getColor();
 584:  g.setColor(Color.YELLOW);
 585: 
 586:  Polygon triangle = new Polygon(new int[] { 0, 18, 36 },
 587:  new int[] { 36, 0, 36 }, 3);
 588:  g.fillPolygon(triangle);
 589: 
 590:  g.setColor(Color.BLACK);
 591: 
 592:  Polygon excl = new Polygon(new int[] { 15, 16, 20, 21 },
 593:  new int[] { 8, 26, 26, 8 }, 4);
 594:  g.drawPolygon(excl);
 595:  g.drawOval(16, 30, 4, 4);
 596: 
 597:  g.setColor(saved);
 598:  g.translate(-x, -y);
 599:  }
 600:  };
 601: 
 602:  /** The icon displayed for MESSAGE_ICON. */
 603:  private static MessageIcon questionIcon = new MessageIcon()
 604:  {
 605:  public void paintIcon(Component c, Graphics g, int x, int y)
 606:  {
 607:  g.translate(x, y);
 608:  Color saved = g.getColor();
 609:  g.setColor(Color.GREEN);
 610: 
 611:  g.fillRect(0, 0, ICON_SIZE, ICON_SIZE);
 612: 
 613:  g.setColor(Color.BLACK);
 614: 
 615:  g.drawOval(11, 2, 16, 16);
 616:  g.drawOval(14, 5, 10, 10);
 617: 
 618:  g.setColor(Color.GREEN);
 619:  g.fillRect(0, 10, ICON_SIZE, ICON_SIZE - 10);
 620: 
 621:  g.setColor(Color.BLACK);
 622: 
 623:  g.drawLine(11, 10, 14, 10);
 624: 
 625:  g.drawLine(24, 10, 17, 22);
 626:  g.drawLine(27, 10, 20, 22);
 627:  g.drawLine(17, 22, 20, 22);
 628: 
 629:  g.drawOval(17, 25, 3, 3);
 630: 
 631:  g.setColor(saved);
 632:  g.translate(-x, -y);
 633:  }
 634:  };
 635: 
 636:  /**
 637:  * Creates a new BasicOptionPaneUI object.
 638:  */
 639:  public BasicOptionPaneUI()
 640:  {
 641:  // Nothing to do here.
 642:  }
 643: 
 644:  /**
 645:  * This method is messaged to add the buttons to the given container.
 646:  *
 647:  * @param container The container to add components to.
 648:  * @param buttons The buttons to add. (If it is an instance of component,
 649:  * the Object is added directly. If it is an instance of Icon, it is
 650:  * packed into a label and added. For all other cases, the string
 651:  * representation of the Object is retreived and packed into a
 652:  * label.)
 653:  * @param initialIndex The index of the component that is the initialValue.
 654:  */
 655:  protected void addButtonComponents(Container container, Object[] buttons,
 656:  int initialIndex)
 657:  {
 658:  if (buttons == null)
 659:  return;
 660:  for (int i = 0; i < buttons.length; i++)
 661:  {
 662:  if (buttons[i] != null)
 663:  {
 664:  Component toAdd;
 665:  if (buttons[i] instanceof Component)
 666:  toAdd = (Component) buttons[i];
 667:  else
 668:  {
 669:  if (buttons[i] instanceof Icon)
 670:  toAdd = new JButton((Icon) buttons[i]);
 671:  else
 672:  toAdd = new JButton(buttons[i].toString());
 673:  hasCustomComponents = true;
 674:  }
 675:  if (toAdd instanceof JButton)
 676:  ((JButton) toAdd).addActionListener(createButtonActionListener(i));
 677:  if (i == initialIndex)
 678:  initialFocusComponent = toAdd;
 679:  container.add(toAdd);
 680:  }
 681:  }
 682:  selectInitialValue(optionPane);
 683:  }
 684: 
 685:  /**
 686:  * This method adds the appropriate icon the given container.
 687:  *
 688:  * @param top The container to add an icon to.
 689:  */
 690:  protected void addIcon(Container top)
 691:  {
 692:  JLabel iconLabel = null;
 693:  Icon icon = getIcon();
 694:  if (icon != null)
 695:  {
 696:  iconLabel = new JLabel(icon);
 697:  configureLabel(iconLabel);
 698:  top.add(iconLabel, BorderLayout.WEST);
 699:  }
 700:  }
 701: 
 702:  /**
 703:  * A helper method that returns an instance of GridBagConstraints to be used
 704:  * for creating the message area.
 705:  *
 706:  * @return An instance of GridBagConstraints.
 707:  */
 708:  private static GridBagConstraints createConstraints()
 709:  {
 710:  GridBagConstraints constraints = new GridBagConstraints();
 711:  constraints.gridx = GridBagConstraints.REMAINDER;
 712:  constraints.gridy = GridBagConstraints.REMAINDER;
 713:  constraints.gridwidth = 0;
 714:  constraints.anchor = GridBagConstraints.LINE_START;
 715:  constraints.fill = GridBagConstraints.NONE;
 716:  constraints.insets = new Insets(0, 0, 3, 0);
 717: 
 718:  return constraints;
 719:  }
 720: 
 721:  /**
 722:  * This method creates the proper object (if necessary) to represent msg.
 723:  * (If msg is an instance of Component, it will add it directly. If it is
 724:  * an icon, then it will pack it in a label and add it. Otherwise, it gets
 725:  * treated as a string. If the string is longer than maxll, a box is
 726:  * created and the burstStringInto is called with the box as the container.
 727:  * The box is then added to the given container. Otherwise, the string is
 728:  * packed in a label and placed in the given container.) This method is
 729:  * also used for adding the inputComponent to the container.
 730:  *
 731:  * @param container The container to add to.
 732:  * @param cons The constraints when adding.
 733:  * @param msg The message to add.
 734:  * @param maxll The max line length.
 735:  * @param internallyCreated Whether the msg is internally created.
 736:  */
 737:  protected void addMessageComponents(Container container,
 738:  GridBagConstraints cons, Object msg,
 739:  int maxll, boolean internallyCreated)
 740:  {
 741:  if (msg == null)
 742:  return;
 743:  hasCustomComponents = internallyCreated;
 744:  if (msg instanceof Object[])
 745:  {
 746:  Object[] arr = (Object[]) msg;
 747:  for (int i = 0; i < arr.length; i++)
 748:  addMessageComponents(container, cons, arr[i], maxll,
 749:  internallyCreated);
 750:  return;
 751:  }
 752:  else if (msg instanceof Component)
 753:  {
 754:  container.add((Component) msg, cons);
 755:  cons.gridy++;
 756:  }
 757:  else if (msg instanceof Icon)
 758:  {
 759:  JLabel label = new JLabel((Icon) msg);
 760:  configureLabel(label);
 761:  container.add(label, cons);
 762:  cons.gridy++;
 763:  }
 764:  else
 765:  {
 766:  // Undocumented behaviour.
 767:  // if msg.toString().length greater than maxll
 768:  // it will create a box and burst the string.
 769:  // otherwise, it will just create a label and re-call 
 770:  // this method with the label o.O
 771:  if (msg.toString().length() > maxll || msg.toString().contains("\n"))
 772:  {
 773:  Box tmp = new Box(BoxLayout.Y_AXIS);
 774:  burstStringInto(tmp, msg.toString(), maxll);
 775:  addMessageComponents(container, cons, tmp, maxll, true);
 776:  }
 777:  else
 778:  {
 779:  JLabel label = new JLabel(msg.toString());
 780:  configureLabel(label);
 781:  addMessageComponents(container, cons, label, maxll, true);
 782:  }
 783:  }
 784:  }
 785: 
 786:  /**
 787:  * This method creates instances of d (recursively if necessary based on
 788:  * maxll) and adds to c.
 789:  *
 790:  * @param c The container to add to.
 791:  * @param d The string to burst.
 792:  * @param maxll The max line length.
 793:  */
 794:  protected void burstStringInto(Container c, String d, int maxll)
 795:  {
 796:  if (d == null || c == null)
 797:  return;
 798: 
 799:  int newlineIndex = d.indexOf('\n');
 800:  String line;
 801:  String remainder;
 802:  if (newlineIndex >= 0 && newlineIndex < maxll)
 803:  {
 804:  line = d.substring(0, newlineIndex);
 805:  remainder = d.substring(newlineIndex + 1);
 806:  }
 807:  else
 808:  {
 809:  line = d.substring(0, maxll);
 810:  remainder = d.substring(maxll);
 811:  }
 812:  JLabel label = new JLabel(line);
 813:  configureLabel(label);
 814:  c.add(label);
 815: 
 816:  // If there is nothing left to burst, then we can stop.
 817:  if (remainder.length() == 0)
 818:  return;
 819: 
 820:  // Recursively call ourselves to burst the remainder of the string, 
 821:  if (remainder.length() > maxll || remainder.contains("\n"))
 822:  burstStringInto(c, remainder, maxll);
 823:  else
 824:  {
 825:  // Add the remainder to the container and be done.
 826:  JLabel l = new JLabel(remainder);
 827:  configureLabel(l);
 828:  c.add(l);
 829:  }
 830:  }
 831: 
 832:  /**
 833:  * This method returns true if the given JOptionPane contains custom
 834:  * components.
 835:  *
 836:  * @param op The JOptionPane to check.
 837:  *
 838:  * @return True if the JOptionPane contains custom components.
 839:  */
 840:  public boolean containsCustomComponents(JOptionPane op)
 841:  {
 842:  return hasCustomComponents;
 843:  }
 844: 
 845:  /**
 846:  * This method creates a button action listener for the given button index.
 847:  *
 848:  * @param buttonIndex The index of the button in components.
 849:  *
 850:  * @return A new ButtonActionListener.
 851:  */
 852:  protected ActionListener createButtonActionListener(int buttonIndex)
 853:  {
 854:  return new ButtonActionListener(buttonIndex);
 855:  }
 856: 
 857:  /**
 858:  * This method creates the button area.
 859:  *
 860:  * @return A new Button Area.
 861:  */
 862:  protected Container createButtonArea()
 863:  {
 864:  JPanel buttonPanel = new JPanel();
 865:  Border b = UIManager.getBorder("OptionPane.buttonAreaBorder");
 866:  if (b != null)
 867:  buttonPanel.setBorder(b);
 868: 
 869:  buttonPanel.setLayout(createLayoutManager());
 870:  addButtonComponents(buttonPanel, getButtons(), getInitialValueIndex());
 871: 
 872:  return buttonPanel;
 873:  }
 874: 
 875:  /**
 876:  * This method creates a new LayoutManager for the button area.
 877:  *
 878:  * @return A new LayoutManager for the button area.
 879:  */
 880:  protected LayoutManager createLayoutManager()
 881:  {
 882:  return new ButtonAreaLayout(getSizeButtonsToSameWidth(), 6);
 883:  }
 884: 
 885:  /**
 886:  * This method creates the message area.
 887:  *
 888:  * @return A new message area.
 889:  */
 890:  protected Container createMessageArea()
 891:  {
 892:  JPanel messageArea = new JPanel();
 893:  Border messageBorder = UIManager.getBorder("OptionPane.messageAreaBorder");
 894:  if (messageBorder != null)
 895:  messageArea.setBorder(messageBorder);
 896: 
 897:  messageArea.setLayout(new BorderLayout());
 898:  addIcon(messageArea);
 899: 
 900:  JPanel rightSide = new JPanel();
 901:  rightSide.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
 902:  rightSide.setLayout(new GridBagLayout());
 903:  GridBagConstraints con = createConstraints();
 904:  
 905:  addMessageComponents(rightSide, con, getMessage(),
 906:  getMaxCharactersPerLineCount(), false);
 907: 
 908:  if (optionPane.getWantsInput())
 909:  {
 910:  Object[] selection = optionPane.getSelectionValues();
 911: 
 912:  if (selection == null)
 913:  inputComponent = new JTextField(15);
 914:  else if (selection.length < 20)
 915:  inputComponent = new JComboBox(selection);
 916:  else
 917:  inputComponent = new JList(selection);
 918:  if (inputComponent != null)
 919:  {
 920:  addMessageComponents(rightSide, con, inputComponent,
 921:  getMaxCharactersPerLineCount(), false);
 922:  resetSelectedValue();
 923:  selectInitialValue(optionPane);
 924:  }
 925:  }
 926: 
 927:  messageArea.add(rightSide, BorderLayout.CENTER);
 928: 
 929:  return messageArea;
 930:  }
 931: 
 932:  /**
 933:  * This method creates a new PropertyChangeListener for listening to the
 934:  * JOptionPane.
 935:  *
 936:  * @return A new PropertyChangeListener.
 937:  */
 938:  protected PropertyChangeListener createPropertyChangeListener()
 939:  {
 940:  return new PropertyChangeHandler();
 941:  }
 942: 
 943:  /**
 944:  * This method creates a Container that will separate the message and button
 945:  * areas.
 946:  *
 947:  * @return A Container that will separate the message and button areas.
 948:  */
 949:  protected Container createSeparator()
 950:  {
 951:  // The reference implementation returns null here. When overriding
 952:  // to return something non-null, the component gets added between
 953:  // the message area and the button area. See installComponents().
 954:  return null;
 955:  }
 956: 
 957:  /**
 958:  * This method creates a new BasicOptionPaneUI for the given component.
 959:  *
 960:  * @param x The component to create a UI for.
 961:  *
 962:  * @return A new BasicOptionPaneUI.
 963:  */
 964:  public static ComponentUI createUI(JComponent x)
 965:  {
 966:  return new BasicOptionPaneUI();
 967:  }
 968: 
 969:  /**
 970:  * This method returns the buttons for the JOptionPane. If no options are
 971:  * set, a set of options will be created based upon the optionType.
 972:  *
 973:  * @return The buttons that will be added.
 974:  */
 975:  protected Object[] getButtons()
 976:  {
 977:  if (optionPane.getOptions() != null)
 978:  return optionPane.getOptions();
 979:  switch (optionPane.getOptionType())
 980:  {
 981:  case JOptionPane.YES_NO_OPTION:
 982:  return new Object[] { YES_STRING, NO_STRING };
 983:  case JOptionPane.YES_NO_CANCEL_OPTION:
 984:  return new Object[] { YES_STRING, NO_STRING, CANCEL_STRING };
 985:  case JOptionPane.OK_CANCEL_OPTION:
 986:  return new Object[] { OK_STRING, CANCEL_STRING };
 987:  case JOptionPane.DEFAULT_OPTION:
 988:  return (optionPane.getWantsInput()) ?
 989:  new Object[] { OK_STRING, CANCEL_STRING } :
 990:  (optionPane.getMessageType() == JOptionPane.QUESTION_MESSAGE) ?
 991:  new Object[] { YES_STRING, NO_STRING, CANCEL_STRING } :
 992:  // ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE
 993:  new Object[] { OK_STRING };
 994:  }
 995:  return null;
 996:  }
 997: 
 998:  /**
 999:  * This method will return the icon the user has set or the icon that will
1000:  * be used based on message type.
1001:  *
1002:  * @return The icon to use in the JOptionPane.
1003:  */
1004:  protected Icon getIcon()
1005:  {
1006:  if (optionPane.getIcon() != null)
1007:  return optionPane.getIcon();
1008:  else
1009:  return getIconForType(optionPane.getMessageType());
1010:  }
1011: 
1012:  /**
1013:  * This method returns the icon for the given messageType.
1014:  *
1015:  * @param messageType The type of message.
1016:  *
1017:  * @return The icon for the given messageType.
1018:  */
1019:  protected Icon getIconForType(int messageType)
1020:  {
1021:  Icon tmp = null;
1022:  switch (messageType)
1023:  {
1024:  case JOptionPane.ERROR_MESSAGE:
1025:  tmp = errorIcon;
1026:  break;
1027:  case JOptionPane.INFORMATION_MESSAGE:
1028:  tmp = infoIcon;
1029:  break;
1030:  case JOptionPane.WARNING_MESSAGE:
1031:  tmp = warningIcon;
1032:  break;
1033:  case JOptionPane.QUESTION_MESSAGE:
1034:  tmp = questionIcon;
1035:  break;
1036:  }
1037:  return tmp;
1038:  // FIXME: Don't cast till the default icons are in.
1039:  // return new IconUIResource(tmp);
1040:  }
1041: 
1042:  /**
1043:  * This method returns the index of the initialValue in the options array.
1044:  *
1045:  * @return The index of the initalValue.
1046:  */
1047:  protected int getInitialValueIndex()
1048:  {
1049:  Object[] buttons = getButtons();
1050: 
1051:  if (buttons == null)
1052:  return -1;
1053: 
1054:  Object select = optionPane.getInitialValue();
1055: 
1056:  for (int i = 0; i < buttons.length; i++)
1057:  {
1058:  if (select == buttons[i])
1059:  return i;
1060:  }
1061:  return 0;
1062:  }
1063: 
1064:  /**
1065:  * This method returns the maximum number of characters that should be
1066:  * placed on a line.
1067:  *
1068:  * @return The maximum number of characteres that should be placed on a
1069:  * line.
1070:  */
1071:  protected int getMaxCharactersPerLineCount()
1072:  {
1073:  return optionPane.getMaxCharactersPerLineCount();
1074:  }
1075: 
1076:  /**
1077:  * This method returns the maximum size.
1078:  *
1079:  * @param c The JComponent to measure.
1080:  *
1081:  * @return The maximum size.
1082:  */
1083:  public Dimension getMaximumSize(JComponent c)
1084:  {
1085:  return getPreferredSize(c);
1086:  }
1087: 
1088:  /**
1089:  * This method returns the message of the JOptionPane.
1090:  *
1091:  * @return The message.
1092:  */
1093:  protected Object getMessage()
1094:  {
1095:  return optionPane.getMessage();
1096:  }
1097: 
1098:  /**
1099:  * This method returns the minimum size of the JOptionPane.
1100:  *
1101:  * @return The minimum size.
1102:  */
1103:  public Dimension getMinimumOptionPaneSize()
1104:  {
1105:  return minimumSize;
1106:  }
1107: 
1108:  /**
1109:  * This method returns the minimum size.
1110:  *
1111:  * @param c The JComponent to measure.
1112:  *
1113:  * @return The minimum size.
1114:  */
1115:  public Dimension getMinimumSize(JComponent c)
1116:  {
1117:  return getPreferredSize(c);
1118:  }
1119: 
1120:  /**
1121:  * This method returns the preferred size of the JOptionPane. The preferred
1122:  * size is the maximum of the size desired by the layout and the minimum
1123:  * size.
1124:  *
1125:  * @param c The JComponent to measure.
1126:  *
1127:  * @return The preferred size.
1128:  */
1129:  public Dimension getPreferredSize(JComponent c)
1130:  {
1131:  Dimension d = optionPane.getLayout().preferredLayoutSize(optionPane);
1132:  Dimension d2 = getMinimumOptionPaneSize();
1133: 
1134:  int w = Math.max(d.width, d2.width);
1135:  int h = Math.max(d.height, d2.height);
1136:  return new Dimension(w, h);
1137:  }
1138: 
1139:  /**
1140:  * This method returns whether all buttons should have the same width.
1141:  *
1142:  * @return Whether all buttons should have the same width.
1143:  */
1144:  protected boolean getSizeButtonsToSameWidth()
1145:  {
1146:  return true;
1147:  }
1148: 
1149:  /**
1150:  * This method installs components for the JOptionPane.
1151:  */
1152:  protected void installComponents()
1153:  {
1154:  // First thing is the message area.
1155:  optionPane.add(createMessageArea());
1156: 
1157:  // Add separator when createSeparator() is overridden to return
1158:  // something other than null.
1159:  Container sep = createSeparator();
1160:  if (sep != null)
1161:  optionPane.add(sep);
1162: 
1163:  // Last thing is the button area.
1164:  optionPane.add(createButtonArea());
1165:  }
1166: 
1167:  /**
1168:  * This method installs defaults for the JOptionPane.
1169:  */
1170:  protected void installDefaults()
1171:  {
1172:  LookAndFeel.installColorsAndFont(optionPane, "OptionPane.background",
1173:  "OptionPane.foreground",
1174:  "OptionPane.font");
1175:  LookAndFeel.installBorder(optionPane, "OptionPane.border");
1176:  optionPane.setOpaque(true);
1177: 
1178:  minimumSize = UIManager.getDimension("OptionPane.minimumSize");
1179: 
1180:  // FIXME: Image icons don't seem to work properly right now.
1181:  // Once they do, replace the synthetic icons with these ones.
1182: 
1183:  /*
1184:  warningIcon = (IconUIResource) defaults.getIcon("OptionPane.warningIcon");
1185:  infoIcon = (IconUIResource) defaults.getIcon("OptionPane.informationIcon");
1186:  errorIcon = (IconUIResource) defaults.getIcon("OptionPane.errorIcon");
1187:  questionIcon = (IconUIResource) defaults.getIcon("OptionPane.questionIcon");
1188:  */
1189:  }
1190: 
1191:  /**
1192:  * This method installs keyboard actions for the JOptionpane.
1193:  */
1194:  protected void installKeyboardActions()
1195:  {
1196:  // Install the input map.
1197:  Object[] bindings =
1198:  (Object[]) SharedUIDefaults.get("OptionPane.windowBindings");
1199:  InputMap inputMap = LookAndFeel.makeComponentInputMap(optionPane,
1200:  bindings);
1201:  SwingUtilities.replaceUIInputMap(optionPane,
1202:  JComponent.WHEN_IN_FOCUSED_WINDOW,
1203:  inputMap);
1204: 
1205:  // FIXME: The JDK uses a LazyActionMap for parentActionMap
1206:  SwingUtilities.replaceUIActionMap(optionPane, getActionMap());
1207:  }
1208: 
1209:  /**
1210:  * Fetches the action map from the UI defaults, or create a new one
1211:  * if the action map hasn't been initialized.
1212:  *
1213:  * @return the action map
1214:  */
1215:  private ActionMap getActionMap()
1216:  {
1217:  ActionMap am = (ActionMap) UIManager.get("OptionPane.actionMap");
1218:  if (am == null)
1219:  {
1220:  am = createDefaultActions();
1221:  UIManager.getLookAndFeelDefaults().put("OptionPane.actionMap", am);
1222:  }
1223:  return am;
1224:  }
1225: 
1226:  private ActionMap createDefaultActions()
1227:  {
1228:  ActionMapUIResource am = new ActionMapUIResource();
1229:  Action action = new OptionPaneCloseAction();
1230: 
1231:  am.put("close", action);
1232:  return am;
1233:  }
1234: 
1235:  /**
1236:  * This method installs listeners for the JOptionPane.
1237:  */
1238:  protected void installListeners()
1239:  {
1240:  propertyChangeListener = createPropertyChangeListener();
1241: 
1242:  optionPane.addPropertyChangeListener(propertyChangeListener);
1243:  }
1244: 
1245:  /**
1246:  * This method installs the UI for the JOptionPane.
1247:  *
1248:  * @param c The JComponent to install the UI for.
1249:  */
1250:  public void installUI(JComponent c)
1251:  {
1252:  if (c instanceof JOptionPane)
1253:  {
1254:  optionPane = (JOptionPane) c;
1255: 
1256:  installDefaults();
1257:  installComponents();
1258:  installListeners();
1259:  installKeyboardActions();
1260:  }
1261:  }
1262: 
1263:  /**
1264:  * Changes the inputValue property in the JOptionPane based on the current
1265:  * value of the inputComponent.
1266:  */
1267:  protected void resetInputValue()
1268:  {
1269:  if (optionPane.getWantsInput() && inputComponent != null)
1270:  {
1271:  Object output = null;
1272:  if (inputComponent instanceof JTextField)
1273:  output = ((JTextField) inputComponent).getText();
1274:  else if (inputComponent instanceof JComboBox)
1275:  output = ((JComboBox) inputComponent).getSelectedItem();
1276:  else if (inputComponent instanceof JList)
1277:  output = ((JList) inputComponent).getSelectedValue();
1278: 
1279:  if (output != null)
1280:  optionPane.setInputValue(output);
1281:  }
1282:  }
1283: 
1284:  /**
1285:  * This method requests focus to the inputComponent (if one is present) and
1286:  * the initialFocusComponent otherwise.
1287:  *
1288:  * @param op The JOptionPane.
1289:  */
1290:  public void selectInitialValue(JOptionPane op)
1291:  {
1292:  if (inputComponent != null)
1293:  {
1294:  inputComponent.requestFocus();
1295:  return;
1296:  }
1297:  if (initialFocusComponent != null)
1298:  initialFocusComponent.requestFocus();
1299:  }
1300: 
1301:  /**
1302:  * This method resets the value in the inputComponent to the
1303:  * initialSelectionValue property.
1304:  * This is package-private to avoid an accessor method.
1305:  */
1306:  void resetSelectedValue()
1307:  {
1308:  if (inputComponent != null)
1309:  {
1310:  Object init = optionPane.getInitialSelectionValue();
1311:  if (init == null)
1312:  return;
1313:  if (inputComponent instanceof JTextField)
1314:  ((JTextField) inputComponent).setText((String) init);
1315:  else if (inputComponent instanceof JComboBox)
1316:  ((JComboBox) inputComponent).setSelectedItem(init);
1317:  else if (inputComponent instanceof JList)
1318:  {
1319:  // ((JList) inputComponent).setSelectedValue(init, true);
1320:  }
1321:  }
1322:  }
1323: 
1324:  /**
1325:  * This method uninstalls all the components in the JOptionPane.
1326:  */
1327:  protected void uninstallComponents()
1328:  {
1329:  optionPane.removeAll();
1330:  buttonContainer = null;
1331:  messageAreaContainer = null;
1332:  }
1333: 
1334:  /**
1335:  * This method uninstalls the defaults for the JOptionPane.
1336:  */
1337:  protected void uninstallDefaults()
1338:  {
1339:  optionPane.setFont(null);
1340:  optionPane.setForeground(null);
1341:  optionPane.setBackground(null);
1342: 
1343:  minimumSize = null;
1344: 
1345:  // FIXME: ImageIcons don't seem to work properly
1346: 
1347:  /*
1348:  warningIcon = null;
1349:  errorIcon = null;
1350:  questionIcon = null;
1351:  infoIcon = null;
1352:  */
1353:  }
1354: 
1355:  /**
1356:  * This method uninstalls keyboard actions for the JOptionPane.
1357:  */
1358:  protected void uninstallKeyboardActions()
1359:  {
1360:  SwingUtilities.replaceUIInputMap(optionPane, JComponent.
1361:  WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
1362:  SwingUtilities.replaceUIActionMap(optionPane, null);
1363:  }
1364: 
1365:  /**
1366:  * This method uninstalls listeners for the JOptionPane.
1367:  */
1368:  protected void uninstallListeners()
1369:  {
1370:  optionPane.removePropertyChangeListener(propertyChangeListener);
1371:  propertyChangeListener = null;
1372:  }
1373: 
1374:  /**
1375:  * This method uninstalls the UI for the given JComponent.
1376:  *
1377:  * @param c The JComponent to uninstall for.
1378:  */
1379:  public void uninstallUI(JComponent c)
1380:  {
1381:  uninstallKeyboardActions();
1382:  uninstallListeners();
1383:  uninstallComponents();
1384:  uninstallDefaults();
1385: 
1386:  optionPane = null;
1387:  }
1388: 
1389:  /**
1390:  * Applies the proper UI configuration to labels that are added to
1391:  * the OptionPane.
1392:  *
1393:  * @param l the label to configure
1394:  */
1395:  private void configureLabel(JLabel l)
1396:  {
1397:  Color c = UIManager.getColor("OptionPane.messageForeground");
1398:  if (c != null)
1399:  l.setForeground(c);
1400:  Font f = UIManager.getFont("OptionPane.messageFont");
1401:  if (f != null)
1402:  l.setFont(f);
1403:  }
1404: }
Overview Package Class Use Source Tree Index Deprecated About
GNU Classpath (0.95)

AltStyle によって変換されたページ (->オリジナル) /