1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.tool;
  28 
  29 import java.awt.Color;
  30 import java.awt.Component;
  31 import java.awt.Container;
  32 import java.awt.Dimension;
  33 import java.awt.Font;
  34 import java.awt.GridBagConstraints;
  35 import java.awt.GridBagLayout;
  36 import java.awt.Image;
  37 import java.awt.KeyboardFocusManager;
  38 import java.awt.LayoutManager;
  39 import java.awt.Toolkit;
  40 import java.awt.Window;
  41 import java.awt.event.ActionEvent;
  42 import java.awt.event.ActionListener;
  43 import java.awt.event.KeyEvent;
  44 import java.net.URL;
  45 import java.util.MissingResourceException;
  46 
  47 import javax.accessibility.Accessible;
  48 import javax.accessibility.AccessibleContext;
  49 import javax.swing.AbstractButton;
  50 import javax.swing.Action;
  51 import javax.swing.BorderFactory;
  52 import javax.swing.BoundedRangeModel;
  53 import javax.swing.Box;
  54 import javax.swing.ButtonGroup;
  55 import javax.swing.DefaultListCellRenderer;
  56 import javax.swing.Icon;
  57 import javax.swing.ImageIcon;
  58 import javax.swing.JButton;
  59 import javax.swing.JCheckBox;
  60 import javax.swing.JCheckBoxMenuItem;
  61 import javax.swing.JComboBox;
  62 import javax.swing.JComponent;
  63 import javax.swing.JDialog;
  64 import javax.swing.JFrame;
  65 import javax.swing.JInternalFrame;
  66 import javax.swing.JLabel;
  67 import javax.swing.JList;
  68 import javax.swing.JMenu;
  69 import javax.swing.JMenuBar;
  70 import javax.swing.JMenuItem;
  71 import javax.swing.JOptionPane;
  72 import javax.swing.JPanel;
  73 import javax.swing.JPopupMenu;
  74 import javax.swing.JProgressBar;
  75 import javax.swing.JRadioButton;
  76 import javax.swing.JRadioButtonMenuItem;
  77 import javax.swing.JRootPane;
  78 import javax.swing.JScrollPane;
  79 import javax.swing.JSlider;
  80 import javax.swing.JSplitPane;
  81 //import javax.swing.JSpinner;
  82 import javax.swing.JTabbedPane;
  83 import javax.swing.JTable;
  84 import javax.swing.JTextArea;
  85 import javax.swing.JTextField;
  86 import javax.swing.JToolBar;
  87 import javax.swing.KeyStroke;
  88 import javax.swing.ListModel;
  89 //import javax.swing.SpinnerModel;
  90 import javax.swing.SwingConstants;
  91 import javax.swing.SwingUtilities;
  92 import javax.swing.border.Border;
  93 import javax.swing.border.TitledBorder;
  94 import javax.swing.table.TableModel;
  95 
  96 import com.sun.javatest.ProductInfo;
  97 import com.sun.javatest.tool.jthelp.ContextHelpManager;
  98 import com.sun.javatest.tool.jthelp.HelpBroker;
  99 import com.sun.javatest.util.I18NResourceBundle;
 100 import java.awt.Dialog;
 101 import java.util.Enumeration;
 102 import java.util.ResourceBundle;
 103 import javax.swing.UIManager;
 104 import javax.swing.plaf.metal.MetalLookAndFeel;
 105 
 106 /**
 107  * A factory for GUI components, providing support for
 108  * internationalization, tool tips, context sensitive help, and on.
 109  * UIFactory objects use a resource bundle specific to the client
 110  * class to provide the internationalization support.
 111  */
 112 public class UIFactory {
 113 
 114     public static enum Colors {
 115         /**
 116          * Color used for highlighting incorrect input fields
 117          */
 118         INPUT_INVALID(local_i18n.getString("colorprefs.colors.input.invalid.defvalue")),
 119         /**
 120          * Color used for highlighting correct input fields
 121          */
 122         INPUT_VALID(local_i18n.getString("colorprefs.colors.input.valid.defvalue")),
 123         /**
 124          * Default background color for input fields
 125          */
 126         INPUT_DEFAULT(local_i18n.getString("colorprefs.colors.input.default.defvalue")),
 127 
 128         MENU_BACKGROUND(UIManager.getColor("Menu.background"), 255, false),
 129         SEPARATOR_FOREGROUND(UIManager.getColor("Separator.foreground"), 255, false),
 130         CONTROL_INFO(Color.RED, 255, false),
 131         CONTROL_SHADOW(Color.RED, 255, false),
 132         TEXT_HIGHLIGHT_COLOR(new JTextField().getSelectionColor(), 255, false),
 133         TEXT_COLOR(new JLabel().getForeground(), 255, false),
 134         TEXT_SELECTED_COLOR(new JTextField().getSelectedTextColor(), 255, false),
 135         WINDOW_BACKGROUND(UIManager.getColor("Panel.background"), 255, false),
 136         PRIMARY_CONTROL_HIGHLIGHT(Color.WHITE, 255, false),
 137         PRIMARY_CONTROL_INFO(Color.BLACK, 255, false),
 138         BUTTON_DISABLED_FOREGROUND(Color.WHITE, 255, false),//UIManager.getDefaults().getColor("Button.disabledForeground")
 139 
 140         // these three are used for icon drawing only
 141         PRIMARY_CONTROL_SHADOW(MetalLookAndFeel.getPrimaryControlShadow(), 255, false),
 142         PRIMARY_CONTROL(MetalLookAndFeel.getPrimaryControl(), 255, false),
 143         PRIMARY_CONTROL_DARK_SHADOW(MetalLookAndFeel.getPrimaryControlDarkShadow(), 255, false),
 144 
 145         BLACK(Color.BLACK, 255, false),
 146         TRANSPARENT(new Color(255, 255, 255, 0), false);
 147 
 148         private final String defaultColor;
 149         private Color color = null;
 150         private boolean configurable;
 151 
 152         Colors(Color defaultColor) {
 153             this(defaultColor, true);
 154         }
 155 
 156         Colors(Color defaultColor, int alpha) {
 157             this(new Color(defaultColor.getRed(), defaultColor.getGreen(), defaultColor.getBlue(), alpha), true);
 158         }
 159 
 160         Colors(Color defaultColor, int alpha, boolean configurable) {
 161             this(new Color(defaultColor.getRed(), defaultColor.getGreen(), defaultColor.getBlue(), alpha), configurable);
 162         }
 163 
 164         Colors(Color defaultColor, boolean configurable) {
 165             this.defaultColor = encodeARGB(defaultColor);
 166             this.configurable = configurable;
 167         }
 168 
 169         Colors(String defaultColor) {
 170             this.defaultColor = defaultColor;
 171             this.configurable = true;
 172         }
 173 
 174         public boolean isConfigurable() {
 175             return configurable;
 176         }
 177 
 178         /**
 179          * Getter for default String-encoded color value. Is used for Color.decode() and
 180          * should be formatted similarly
 181          *
 182          * @return Default String-encoded color value
 183          */
 184         public String getDefaultValue() {
 185             return defaultColor;
 186         }
 187 
 188         /**
 189          * Getter for current color value. It is loaded from preferences if no color is set
 190          * previously.
 191          *
 192          * @return Current color value
 193          */
 194         public Color getValue() {
 195             if(color == null) {
 196                 color = readColorFromPreferences();
 197             }
 198             return color;
 199         }
 200 
 201         /**
 202          * Setter for current color value.
 203          *
 204          * @return Old color value
 205          */
 206         public Color setValue(Color c) {
 207             Color t = color;
 208             if (configurable)
 209                 color = c;
 210             return t;
 211         }
 212 
 213         /**
 214          * Get color name used in preferences file. It is formed from enum name.
 215          * E.g. colors.input.invalid for INPUT_INVALID
 216          *
 217          * @return Color name used in preferences file
 218          */
 219         public String getPreferencesName() {
 220             return "colors." + this.name().toLowerCase().replaceAll("_", ".");
 221         }
 222 
 223         /**
 224          * Read color value from preferences ignoring current color value that is
 225          * returned by getValue();
 226          *
 227          * @return Color value from preferences file
 228          */
 229         public Color readColorFromPreferences() {
 230             return decodeRGBA(Preferences.access().getPreference(this.getPreferencesName(), this.getDefaultValue()));
 231         }
 232 
 233         /**
 234          * Find Colors by color preferences name.
 235          *
 236          * @param prefsName Color preferences name (e.g. "colors.input.default")
 237          * @throws IllegalArgumentException in case there is no Colors with such
 238          * name
 239          * @return Colors associated with such preferences name
 240          */
 241         public static Colors valueOfByPreferencesName(String prefsName) {
 242             return Colors.valueOf(prefsName.replaceFirst("colors.", "").toUpperCase().replaceAll("\\.", "_"));
 243         }
 244 
 245         /**
 246          * Get Color by colors preferences name.
 247          *
 248          * @param prefsName Color preferences name (e.g. "colors.input.default")
 249          * @return Color if Preferences contain this color. Returns default value if exists<br>
 250          * null otherwise
 251          */
 252         public static Color getColorByPreferencesName(String prefsName) {
 253             Preferences prefs = Preferences.access();
 254             try {
 255                 Colors c = valueOfByPreferencesName(prefsName); // IllegalArgumentException if such Colors doesn't exist
 256 
 257                 return c.getValue();
 258             } catch(IllegalArgumentException e) {
 259                 String color = prefs.getPreference(prefsName); // try to find color in preferences anyway
 260                 return color == null ? null : decodeRGBA(color);
 261             }
 262         }
 263 
 264         /**
 265          * Get array with all colors names used in preferences
 266          *
 267          * @return Names array
 268          */
 269         public static String[] getColorsNames() {
 270             Colors[] values = Colors.values();
 271             String temp[] = new String[values.length];
 272             for(int i = 0; i < values.length; i++) {
 273                 temp[i] = values[i].getPreferencesName();
 274             }
 275             return temp;
 276         }
 277 
 278         public static Color decodeRGBA(String color) throws NumberFormatException {
 279             try {
 280                 if (color.startsWith("0x") && color.length() == 10) {
 281                     Long colorCode = Long.decode(color);
 282                     int A = (int) (colorCode & 0xFF);
 283                     colorCode >>= 8;
 284                     int B = (int) (colorCode & 0xFF);
 285                     colorCode >>= 8;
 286                     int G = (int) (colorCode & 0xFF);
 287                     colorCode >>= 8;
 288                     int R = (int) (colorCode & 0xFF);
 289                     colorCode >>= 8;
 290                     return new Color(R, G, B, A);
 291                 } else {
 292                     return Color.decode(color);
 293                 }
 294             } catch(Exception e) {
 295                 return Color.red;
 296             }
 297         }
 298 
 299         public static String encodeARGB(Color color) {
 300             if(color == null)
 301                 return "";
 302             return String.format("0x%02x%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
 303         }
 304     }
 305 
 306     public static Font getBaseFont() {
 307         return baseFont;
 308     }
 309 
 310     /**
 311      * Get invalid input color (red by default)
 312      * @return Color of invalid input
 313      */
 314     public static Color getInvalidInputColor() {
 315         return Colors.INPUT_INVALID.getValue();
 316     }
 317 
 318     /**
 319      * Set invalid input color
 320      * @param newColor new invalid input color
 321      */
 322     public static void setInvalidInputColor(Color newColor) {
 323         Colors.INPUT_INVALID.setValue(newColor);
 324     }
 325 
 326     /**
 327      * Get valid input color (green by default)
 328      * @return Color of valid input
 329      */
 330     public static Color getValidInputColor() {
 331         return Colors.INPUT_VALID.getValue();
 332     }
 333 
 334     /**
 335      * Set valid input color
 336      * @param newColor new valid input color
 337      */
 338     public static void setValidInputColor(Color newColor) {
 339         Colors.INPUT_VALID.setValue(newColor);
 340     }
 341 
 342     /**
 343      * Get default input color (while by default)
 344      * @return Color of default input
 345      */
 346     public static Color getDefaultInputColor() {
 347         return Colors.INPUT_DEFAULT.getValue();
 348     }
 349 
 350     /**
 351      * Set default input color
 352      * @param newColor new default input color
 353      */
 354     public static void setDefaultInputColor(Color newColor) {
 355         Colors.INPUT_DEFAULT.setValue(newColor);
 356     }
 357 
 358     /**
 359      * Set Color by preferences name
 360      * @param name Color's preferences name
 361      * @param c new Color to set
 362      */
 363     public static void setColorByName(String name, Color c) {
 364         Colors.valueOfByPreferencesName(name).setValue(c);
 365     }
 366 
 367     /**
 368      * Set all colors to default values
 369      */
 370     public static void setDefaultColors() {
 371         Preferences pref = Preferences.access();
 372         Colors colors[] = Colors.values();
 373         for(Colors c: colors) {
 374             pref.setPreference(c.getPreferencesName(), c.getDefaultValue());
 375         }
 376     }
 377 
 378     /**
 379      * Add Preferences observer to color changes
 380      * @param observer
 381      */
 382     public static void addColorChangeObserver(Preferences.Observer observer) {
 383         Preferences.access().addObserver(Colors.getColorsNames(), observer);
 384     }
 385 
 386     /**
 387      * Creates a color-choosing button with background color set by preferences color name
 388      * @param cs preferences color name. Used to set background color and is set as JButton.name
 389      * @param label JLabel for button
 390      * @param l ActionListener for button
 391      * @return color-choosing button
 392      */
 393     public JButton createColorChooseButton(String cs, JLabel label, ActionListener l) {
 394         JButton b = new JButton(" ");
 395         Color c = Colors.getColorByPreferencesName(cs);
 396         b.setBackground(c);
 397         b.setSize(14, 14);
 398         b.setText(" ");
 399         b.setName(cs);
 400         if(l != null)
 401             b.addActionListener(l);
 402         if(label != null)
 403             label.setLabelFor(b);
 404         return b;
 405     }
 406 
 407     /**
 408      * Create a UIFactory object for a specific class.
 409      * The class is used to determine the resource bundle
 410      * for i18n strings; the bundle is named i18n.properties
 411      * in the same package as the specified class.
 412      * @param c the class used to determine the i18n properties
 413      * @param helpBroker the help broker to be used when creating help buttons
 414      */
 415     public UIFactory(Class<?> c, HelpBroker helpBroker) {
 416         this(c, null, helpBroker);
 417     }
 418 
 419     /**
 420      * Create a UIFactory object for a specific component.
 421      * The component's class is used to determine the resource bundle
 422      * for i18n strings; the bundle is named i18n.properties
 423      * in the same package as the specified class.
 424      * @param c the component used to determine the i18n properties
 425      * @param helpBroker the help broker to be used when creating help buttons
 426      */
 427     public UIFactory(Component c, HelpBroker helpBroker) {
 428         this(c.getClass(), c, helpBroker);
 429     }
 430 
 431     /**
 432      * Create a UIFactory object for a specific class.
 433      * The class is used to determine the resource bundle
 434      * for i18n strings; the bundle is named i18n.properties
 435      * in the same package as the specified class.
 436      * @param c the class used to determine the i18n properties
 437      * @param p the parent component to be used for any dialogs that are created
 438      * @param helpBroker the help broker to be used when creating help buttons
 439      */
 440     public UIFactory(Class<?> c, Component p, HelpBroker helpBroker) {
 441         this.helpBroker = helpBroker;
 442         clientClass = c;
 443         parent = p;
 444         i18n = I18NResourceBundle.getBundleForClass(c);
 445     }
 446 
 447     /**
 448      * Set the parent component to be used for dialogs created by this factory.
 449      * This setting cannot be changed after it is set.
 450      *
 451      * @param p The parent component, should not be null.
 452      */
 453     public void setDialogParent(Component p) {
 454         if (parent != null && parent != p)
 455             throw new IllegalStateException();
 456         parent = p;
 457     }
 458 
 459     /**
 460      * Get the screen resolution, in dots per inch, as provided
 461      * by the default AWT toolkit.
 462      * @return the screen resolution, in dots per inch
 463      */
 464     public int getDotsPerInch() {
 465         return DOTS_PER_INCH;
 466     }
 467 
 468     /**
 469      * Get the help broker associated with this factory.
 470      * @return the help broker associated with this factory
 471      */
 472     public HelpBroker getHelpBroker() {
 473         return helpBroker;
 474     }
 475 
 476     /**
 477      * Get the resource bundle used to obtain the resources for the
 478      * components create by this factory.
 479      * @return the resource bundle used to obtain the resources for the
 480      * components create by this factory
 481      */
 482     public I18NResourceBundle getI18NResourceBundle() {
 483         return i18n;
 484     }
 485 
 486     /**
 487      * Get a keycode from the resource bundle.
 488      * @param key the name of the resource to be returned
 489      * @return the first character of the string that was found
 490      */
 491     public int getI18NMnemonic(String key) {
 492         String keyString = getI18NString(key);
 493         KeyStroke keyStroke = KeyStroke.getKeyStroke(keyString);
 494         if (keyStroke != null)
 495             return keyStroke.getKeyCode();
 496         else
 497             //System.err.println("WARNING: bad mnemonic keystroke for " + key + ": " + keyString);
 498             return 0;
 499     }
 500 
 501     /**
 502      * Get a color from the resource bundle.
 503      * @param key the base name of the resource to be returned
 504      * @return the color identified in the resource
 505      */
 506     public Color getI18NColor(String key) {
 507         String value = i18n.getString(key + ".clr");
 508         try {
 509             if (value != null)
 510                 return Color.decode(value);
 511         }
 512         catch (Exception e) {
 513             // ignore
 514         }
 515         return Color.BLACK;
 516     }
 517 
 518     /**
 519      * Get a string from the resource bundle.
 520      * @param key the name of the resource to be returned
 521      * @return the string that was found
 522      */
 523     public String getI18NString(String key) {
 524         return i18n.getString(key);
 525     }
 526 
 527     /**
 528      * Get a string from the resource bundle.
 529      * @param key the name of the resource to be returned
 530      * @param arg an argument to be formatted into the result using
 531      * {@link java.text.MessageFormat#format}
 532      * @return the formatted string
 533      */
 534     public String getI18NString(String key, Object arg) {
 535         return i18n.getString(key, arg);
 536     }
 537 
 538     /**
 539      * Get a string from the resource bundle.
 540      * @param key the name of the resource to be returned
 541      * @param args an array of arguments to be formatted into the result using
 542      * {@link java.text.MessageFormat#format}
 543      * @return the formatted string
 544      */
 545     public String getI18NString(String key, Object[] args) {
 546         return i18n.getString(key, args);
 547     }
 548 
 549     /**
 550      * Set the help ID for the context-sensitive help for a component.
 551      * @param comp the component for which to set the help ID
 552      * @param helpID the help ID identifying the context sensitive help for
 553      * the component
 554      */
 555     public void setHelp(final Component comp, final String helpID) {
 556         if (helpID == null)
 557             throw new NullPointerException();
 558 
 559         ContextHelpManager.setHelpIDString(comp, helpID);
 560 
 561         if (comp instanceof JDialog) {
 562             JDialog d = (JDialog) comp;
 563             ContextHelpManager.setHelpIDString(d.getRootPane(), helpID);
 564             Desktop.addHelpDebugListener(d);
 565 
 566             final JComponent rootPane = d.getRootPane();
 567             KeyStroke keystroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, false);
 568             rootPane.registerKeyboardAction(new ActionListener(){
 569                 @Override
 570                 public void actionPerformed(ActionEvent e) {
 571                     if (helpBroker != null){
 572                         helpBroker.displayCurrentID(ContextHelpManager.getHelpIDString(rootPane));
 573                     }
 574                 }
 575             }, keystroke, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 576 
 577         }
 578         else{
 579             if (comp instanceof JComponent){
 580                 KeyStroke keystroke = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, false);
 581                 ((JComponent)comp).registerKeyboardAction(new ActionListener(){
 582 
 583                     @Override
 584                     public void actionPerformed(ActionEvent e) {
 585                         if (helpBroker != null){
 586                             helpBroker.displayCurrentID(ContextHelpManager.getHelpIDString(comp));
 587                         }
 588                     }
 589                 }, keystroke, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 590             }
 591 
 592         }
 593 
 594     }
 595 
 596     /**
 597      * Set a tool tip for a component from a resource in the factory's resource
 598      * bundle.  <br>
 599      * By convention, tool tip resources end in ".tip".  Most
 600      * components created by this factory will already have a tool tip set, so
 601      * this method need not be called for them. <br>
 602      * Also, the component's accessible description text will automatically
 603      * be set to the supplied tooltip text.<br>
 604      * The resources used are:
 605      * <table>
 606      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the component
 607      * </table>
 608      * @param c the component for which to set the tool tip
 609      * @param uiKey the base name of the resource to be used
 610      */
 611     public void setToolTip(JComponent c, String uiKey) {
 612         String text = getI18NString(uiKey + ".tip");
 613         c.setToolTipText(text);
 614 
 615         // workaround - tooltip doesn't get copied from this component
 616         // see JComponent.AccessibleJComponent.getToolTipText()
 617         c.getAccessibleContext().setAccessibleDescription(text);
 618     }
 619 
 620     /**
 621      * Sets only the accessible description for the given context, using the
 622      * given key.
 623      * <table>
 624      * <tr><td><i>uiKey</i>.desc  <td>accessible description
 625      * </table>
 626      * @param c the component to modify
 627      * @param uiKey the base name of the resource to be used
 628      * @see #setAccessibleDescription(AccessibleContext,String)
 629      */
 630     public void setAccessibleDescription(Component c, String uiKey) {
 631         setAccessibleDescription(c.getAccessibleContext(), uiKey);
 632     }
 633 
 634     /**
 635      * Sets only the accessible description for the given context, using the
 636      * given key.
 637      * <table>
 638      * <tr><td><i>uiKey</i>.desc  <td>accessible description
 639      * </table>
 640      * @param c the context object to modify
 641      * @param uiKey the base name of the resource to be used
 642      */
 643     public void setAccessibleDescription(AccessibleContext c, String uiKey) {
 644         String text = getI18NString(uiKey + ".desc");
 645         c.setAccessibleDescription(text);
 646     }
 647 
 648     /**
 649      * Sets only the accessible name for the given context, using the
 650      * given key.
 651      * @param c the component object to modify
 652      * @param uiKey the base name of the resource to be used
 653      * @see #setAccessibleName(AccessibleContext,String)
 654      */
 655     public void setAccessibleName(Component c, String uiKey) {
 656         setAccessibleName(c.getAccessibleContext(), uiKey);
 657     }
 658 
 659     /**
 660      * Sets only the accessible name for the given context, using the
 661      * given key.
 662      * <table>
 663      * <tr><td><i>uiKey</i>.name  <td>accessible name
 664      * </table>
 665      * @param c the context object to modify
 666      * @param uiKey the base name of the resource to be used
 667      */
 668     public void setAccessibleName(AccessibleContext c, String uiKey) {
 669         String text = getI18NString(uiKey + ".name");
 670         c.setAccessibleName(text);
 671     }
 672 
 673     /**
 674      * Sets the accessible name and description for the given
 675      * component.
 676      * @param c the component object to modify
 677      * @param uiKey the base name of the resource to be used
 678      * @see #setAccessibleInfo(AccessibleContext,String)
 679      */
 680     public void setAccessibleInfo(Component c, String uiKey) {
 681         setAccessibleInfo(c.getAccessibleContext(), uiKey);
 682     }
 683 
 684     /**
 685      * Sets the accessibility name and description for the given context
 686      * using the given key as the base.
 687      * The resources used are:
 688      * <table>
 689      * <tr><td><i>uiKey</i>.name  <td>accessible name
 690      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
 691      * </table>
 692      * @param c the context object to modify
 693      * @param uiKey the base name of the resource to be used
 694      */
 695     public void setAccessibleInfo(AccessibleContext c, String uiKey) {
 696         setAccessibleDescription(c, uiKey);
 697         setAccessibleName(c, uiKey);
 698     }
 699 
 700 
 701     //----------------------------------------------------------------------------
 702     //
 703     // borders
 704 
 705     /**
 706      * Create a titled border, using a resource to specify the title. <br>
 707      * The resource used is:
 708      * <table>
 709      * <tr><td><i>uiKey</i>.bdr  <td>the text for the title
 710      * </table>
 711      * @param uiKey the base name of the resource to be used
 712      * @return the border that was created
 713      */
 714     public Border createTitledBorder(String uiKey) {
 715         return BorderFactory.createTitledBorder(null, getI18NString(uiKey + ".bdr"), TitledBorder.LEADING, TitledBorder.DEFAULT_JUSTIFICATION, getBaseFont(), Colors.TEXT_COLOR.getValue());
 716     }
 717 
 718     //----------------------------------------------------------------------------
 719     //
 720     // white space
 721 
 722     /**
 723      * Create a horizontal filler that expands to fill the available space.
 724      * The name of the glue component will be set to <i>uikey</i>.  No resource
 725      * strings are required at this time.
 726      * @param uiKey the base name of the resource to be used
 727      * @return a filler component that expands to fill the available space
 728      */
 729     public Component createHorizontalGlue(String uiKey) {
 730         Component c = Box.createHorizontalGlue();
 731         c.setName(uiKey);
 732         c.setFocusable(false);
 733         return c;
 734     }
 735 
 736     /**
 737      * Create a filler that expands to fill the available space.
 738      * @param uiKey the base name of the resource to be used
 739      * @return a filler component that expands to fill the available space
 740      */
 741     public Component createGlue(String uiKey) {
 742         Component c = Box.createGlue();
 743         c.setName(uiKey);
 744         c.setFocusable(false);
 745         return c;
 746     }
 747 
 748 
 749     /**
 750      * Create a horizontal filler of a given width.
 751      * @param width the desired width of the filler component
 752      * @return a filler component of a given width
 753      */
 754     public Component createHorizontalStrut(int width) {
 755         Component c = Box.createHorizontalStrut(width);
 756         c.setFocusable(false);
 757         return c;
 758     }
 759 
 760 
 761     //----------------------------------------------------------------------------
 762     //
 763     // buttons
 764 
 765     /**
 766      * Create a button, using resources to specify the name and the tool tip. <br>
 767      * The resources used are:
 768      * <table>
 769      * <tr><td><i>uiKey</i>.btn  <td>the name for the button
 770      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 771      * </table>
 772      * In addition, the name of the button and the action command
 773      * for the button is set to <i>uiKey</i>.
 774      * @param uiKey the base name of the resources to be used
 775      * @return the button that was created
 776      * @see #createHelpButton
 777      * @see #createIconButton
 778      */
 779     public JButton createButton(String uiKey) {
 780         JButton b = new JButton(getI18NString(uiKey + ".btn"));
 781         b.setActionCommand(uiKey);
 782         b.setName(uiKey);
 783         setMnemonic(b, uiKey);
 784         setToolTip(b, uiKey);
 785         return b;
 786     }
 787 
 788     /**
 789      * Create a button based on the information in an Action.
 790      * @param a the Action for which to define the button
 791      * @return the button that was created
 792      */
 793     public JButton createButton(Action a) {
 794         JButton b = new JButton(a);
 795         b.setName((String) (a.getValue(Action.NAME)));
 796         return b;
 797     }
 798 
 799     /**
 800      * Create a button containing an Icon.
 801      * @param uiKey the base name of the resource to be used
 802      * @param icon the icon to appear in the button
 803      * @return the button that was created
 804      */
 805     public JButton createButton(String uiKey, Icon icon) {
 806         JButton b = new JButton(icon);
 807         b.setName(uiKey);
 808         setMnemonic(b, uiKey);
 809         setToolTip(b, uiKey);
 810         return b;
 811     }
 812 
 813     /**
 814      * Create a button, using resources to specify the name and the tool tip,
 815      * and with a specified ActionListener. <br>
 816      * The resources used are:
 817      * <table>
 818      * <tr><td><i>uiKey</i>.btn  <td>the name for the button
 819      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 820      * </table>
 821      * In addition, the name of the button and the action command
 822      * for the button is set to <i>uiKey</i>.
 823      * @param uiKey the base name of the resources to be used
 824      * @param l the ActionListener to be add to the button
 825      * @return the button that was created
 826      */
 827     public JButton createButton(String uiKey, ActionListener l) {
 828         JButton b = createButton(uiKey);
 829         b.addActionListener(l);
 830         return b;
 831     }
 832 
 833     /**
 834      * Create a button, using resources to specify the name and the tool tip,
 835      * and with a specified ActionListener and action command. <br>
 836      * The resources used are:
 837      * <table>
 838      * <tr><td><i>uiKey</i>.btn  <td>the name for the button
 839      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 840      * </table>
 841      * In addition, the name of the button is set to <i>uiKey</i>.
 842      * @param uiKey the base name of the resources to be used
 843      * @param l the ActionListener to be add to the button
 844      * @param cmd the action command to be set for the button
 845      * @return the button that was created
 846      */
 847     public JButton createButton(String uiKey, ActionListener l, String cmd) {
 848         JButton b = createButton(uiKey);
 849         b.setActionCommand(cmd);
 850         b.addActionListener(l);
 851         return b;
 852     }
 853 
 854     /**
 855      * Constant to identify the cancellation option.
 856      */
 857     public static final String CANCEL = "cancel";
 858 
 859     /**
 860      * Special method to create a cancel button.  Differs from a
 861      * standard button because it does not require a mnemonic, per
 862      * the Java Look and Feel standard.
 863      * @param uiKey key to use to get the tooltip with
 864      * @return the button that was created
 865      */
 866     public JButton createCancelButton(String uiKey) {
 867         return createCancelButton(uiKey, closeListener);
 868     }
 869 
 870     /**
 871      * Special method to create a cancel button.  Differs from a
 872      * standard button because it does not require a mnemonic, per
 873      * the Java Look and Feel standard.
 874      * @param uiKey key to use to get the tooltip with
 875      * @param l listener to attach to the created button
 876      * @return the button that was created
 877      */
 878     public JButton createCancelButton(String uiKey, ActionListener l) {
 879         JButton b;
 880 
 881         I18NResourceBundle save_i18n = i18n;
 882         try {
 883             i18n = local_i18n;
 884             b = new JButton(getI18NString("uif.cancel.btn"));
 885             // no mnemonic for Cancel buttons
 886         }
 887         finally {
 888             i18n = save_i18n;
 889         }
 890 
 891         b.setActionCommand(CANCEL);
 892         b.addActionListener(l);
 893         b.setName(uiKey);
 894         setToolTip(b, uiKey);
 895         return b;
 896     }
 897 
 898     /**
 899      * Create a Close button, that will close the containing window when pressed,
 900      * using a resource to specify the information for the button.  <br>
 901      * The resources used are:
 902      * <table>
 903      * <tr><td><i>uiKey</i>.btn  <td>the name for the button
 904      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button
 905      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 906      * </table>
 907      * In addition, the name of the button is set to <i>uiKey</i>.
 908      * @param uiKey the base name of the resources to be used
 909      * @return the button that was created
 910      * @see #createButton
 911      */
 912     public JButton createCloseButton(String uiKey) {
 913         return createCloseButton(uiKey, true);
 914     }
 915 
 916     /**
 917      * Create a Close button, that will close the containing window when pressed,
 918      * using a resource to specify the information for the button.  <br>
 919      * The resources used are:
 920      * <table>
 921      * <tr><td><i>uiKey</i>.btn  <td>the name for the button
 922      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button, if required
 923      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 924      * </table>
 925      * In addition, the name of the button is set to <i>uiKey</i>.
 926      * @param uiKey the base name of the resources to be used
 927      * @param needMnemonic a boolean indicating whether or not a mnemonic should be
 928      * set on the button. If the button is going to be the default button for a
 929      * dialog, it does not need a mnemonic.
 930      * @return the button that was created
 931      * @see #createButton
 932      */
 933     public JButton createCloseButton(String uiKey, boolean needMnemonic) {
 934         JButton b = new JButton(getI18NString(uiKey + ".btn"));
 935         b.setName(uiKey);
 936         if (needMnemonic)
 937             setMnemonic(b, uiKey);
 938         setToolTip(b, uiKey);
 939         b.addActionListener(closeListener);
 940         return b;
 941     }
 942 
 943     /**
 944      * Create a Help button, that will display a specific help topic when pressed,
 945      * using a resource to specify the tool tip for the button.  <br>
 946      * The resource used is:
 947      * <table>
 948      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 949      * </table>
 950      * In addition, the name of the button is set to <i>uiKey</i>.
 951      * @param uiKey the base name of the resources to be used
 952      * @param helpID the help ID for the help topic to be displayed when the
 953      * button is pressed
 954      * @return the button that was created
 955      * @see #createButton
 956      */
 957     public JButton createHelpButton(String uiKey, final String helpID) {
 958         JButton hb = createButton(uiKey);
 959         hb.addActionListener(new ActionListener() {
 960             @Override
 961             public void actionPerformed(ActionEvent e) {
 962                 if (helpBroker != null) {
 963                     helpBroker.displayCurrentID(helpID);
 964                 }
 965             }
 966         });
 967 
 968         return hb;
 969     }
 970 
 971     /**
 972      * Create a button containing an icon, using resources to specify the
 973      * icon image and the tool tip. <br>
 974      * The resources used are:
 975      * <table>
 976      * <tr><td><i>uiKey</i>.icon <td>the name of the resource for the icon image
 977      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 978      * </table>
 979      * @param uiKey the base name of the resource to be used
 980      * @return the button that was created
 981      */
 982     public JButton createIconButton(String uiKey) {
 983         JButton b = createButton(uiKey, createIcon(uiKey));
 984         b.setBorder(BorderFactory.createEmptyBorder());
 985         return b;
 986     }
 987 
 988     /**
 989      * Create a button containing an icon, using resources to specify the
 990      * icon image and the tool tip. <br>
 991      * The resources used are:
 992      * <table>
 993      * <tr><td><i>uiKey</i>.icon <td>the name of the resource for the icon image
 994      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
 995      * </table>
 996      * @param uiKey the base name of the resource to be used
 997      * @param l the action listener to attach to the new button
 998      * @return the button that was created
 999      */
1000     public JButton createIconButton(String uiKey, ActionListener l) {
1001         JButton b = createButton(uiKey, createIcon(uiKey));
1002         b.addActionListener(l);
1003         return b;
1004     }
1005 
1006     // note this uses local_i18n, not the client i18n
1007     private JButton createOptionButton(String uiKey) {
1008         I18NResourceBundle save_i18n = i18n;
1009         try {
1010             i18n = local_i18n;
1011             JButton b = createButton(uiKey, new ActionListener() {
1012                     public void actionPerformed(ActionEvent e) {
1013                         Component c = (Component) (e.getSource());
1014                         JOptionPane op = (JOptionPane) SwingUtilities.getAncestorOfClass(JOptionPane.class, c);
1015                         op.setValue(c); // JOptionPane expects the value to be set to the selected button
1016                         op.setVisible(false);
1017                     }
1018                 });
1019             return b;
1020         }
1021         finally {
1022             i18n = save_i18n;
1023         }
1024     }
1025 
1026     /**
1027      * Create a radio button, using resources to specify the name and tool tip. <br>
1028      * The button is initially set to <code>false</code>.
1029      * The resources used are:
1030      * <table>
1031      * <tr><td><i>uiKey</i>.rb  <td>the label for the button
1032      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
1033      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button
1034      * </table>
1035      * In addition, the name of the button is set to <i>uiKey</i>.
1036      * @param uiKey the base name of the resources to be used
1037      * @param group the group to which the check box will be added
1038      * @return the radio button that was created
1039      * @see #createButton
1040      * @see #createCheckBox
1041      */
1042     public JRadioButton createRadioButton(String uiKey, ButtonGroup group) {
1043         String text = getI18NString(uiKey + ".rb");
1044         JRadioButton btn = new JRadioButton(text, true);
1045         btn.setName(uiKey);
1046         btn.setSelected(false); // workaround Merlin bug
1047         setMnemonic(btn, uiKey);
1048         setToolTip(btn, uiKey);
1049         group.add(btn);
1050         return btn;
1051     }
1052 
1053     /**
1054      * Set the mnemonic a button.
1055      * The resources used are:
1056      * <table>
1057      * <tr><td><i>uiKey</i>.mne <td>The keystroke to use
1058      * </table>
1059      * @param b the button to modify
1060      * @param uiKey the base name of the resources to be used
1061      * @see javax.swing.KeyStroke
1062      */
1063     public void setMnemonic(AbstractButton b, String uiKey) {
1064         // NOTE: Swing is misleading; it uses an integer value for the mnemonic
1065         // but according to SwingUtilities.findDisplayedMnemonicIndex it is always
1066         // the literal character for the mnemonic, and not anything fancy like
1067         // an integer keycode
1068         int mne = getI18NMnemonic(uiKey + ".mne");
1069         if (mne != 0)
1070             b.setMnemonic(mne);
1071     }
1072 
1073     //----------------------------------------------------------------------------
1074     //
1075     // check boxes
1076 
1077     /**
1078      * Create a check box, using resources to specify the name and the tool tip. <br>
1079      * The resources used are:
1080      * <table>
1081      * <tr><td><i>uiKey</i>.ckb  <td>the name for the check box
1082      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
1083      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button
1084      * </table>
1085      * In addition, the name of the check box is set to <i>uiKey</i>.
1086      * @param uiKey the base name of the resources to be used
1087      * @return the check box that was created
1088      * @see #createCheckBoxMenuItem
1089      */
1090     public JCheckBox createCheckBox(String uiKey) {
1091         return createCheckBox(uiKey, false, null);
1092     }
1093 
1094     /**
1095      * Create a check box, using resources to specify the name and the tool tip. <br>
1096      * The resources used are:
1097      * <table>
1098      * <tr><td><i>uiKey</i>.ckb  <td>the name for the check box
1099      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
1100      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button
1101      * </table>
1102      * In addition, the name of the check box is set to <i>uiKey</i>.
1103      * @param uiKey the base name of the resources to be used
1104      * @param state the initial state of the check box
1105      * @return the check box that was created
1106      * @see #createCheckBoxMenuItem
1107      */
1108     public JCheckBox createCheckBox(String uiKey, boolean state) {
1109         return createCheckBox(uiKey, state, null);
1110     }
1111 
1112     /**
1113      * Create a check box, using resources to specify the name and the tool tip,
1114      * within a specified button group. <br>
1115      * The resources used are:
1116      * <table>
1117      * <tr><td><i>uiKey</i>.ckb  <td>the name for the check box
1118      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the button
1119      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the button
1120      * </table>
1121      * In addition, the name of the check box is set to <i>uiKey</i>.
1122      * @param uiKey the base name of the resources to be used
1123      * @param state the initial state of the check box
1124      * @param group the group to which the check box will be added
1125      * @return the check box that was created
1126      */
1127     public JCheckBox createCheckBox(String uiKey, boolean state, ButtonGroup group) {
1128         String ckbKey = uiKey + ".ckb";
1129         JCheckBox b = new JCheckBox(getI18NString(ckbKey), state);
1130         b.setName(uiKey);
1131         if (group != null)
1132             group.add(b);
1133         setMnemonic(b, uiKey);
1134         setToolTip(b, uiKey);
1135         return b;
1136     }
1137 
1138 
1139     //----------------------------------------------------------------------------
1140     //
1141     // choice lists
1142 
1143     /**
1144      * Create a choice item, using resources to specify the choices and the
1145      * tool tip. <br>
1146      * The resources used are:
1147      * <table>
1148      * <tr><td><i>uiKey</i>.<i>choiceKeys<sub>i</sub></i>.chc  <td>the choice to appear in the item, for 0 &lt;= i &lt; choiceKeys.length
1149      * <tr><td><i>uiKey</i>.name <td>the accessible name for the selector
1150      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the choice item
1151      * </table>
1152      * In addition, the name of the choice is set to <i>uiKey</i>.
1153      * Note: the choice item is created with the choices set to the names
1154      * of the resources used -- not the values. This means that the client can
1155      * examine and manipulate the choices, including the selected choice,
1156      * as location-independent resource names. A custom renderer is used to
1157      * ensure that the correctly localized value is displayed to the user.
1158      * @param uiKey the base name of the resources to be used for the menu
1159      * @param choiceKeys an array of strings used to construct the resource
1160      * names for the choices.
1161      * @return the choice item that was created
1162      * @see #createLiteralChoice
1163      */
1164     public JComboBox<String> createChoice(final String uiKey, final String[] choiceKeys) {
1165         return createChoice(uiKey, choiceKeys, false);
1166     }
1167 
1168     /**
1169      * Same as the two parameter <code>createChoice</code>, except you can
1170      * make this an mutable choice component (freeform editing of the
1171      * response).  If the component is to be editable, an additional
1172      * <i>uiKey</i>.ed resource is needed to set the component name of the
1173      * editable field which will be onscreen.
1174      * @param uiKey the base name of the resources to be used for the menu
1175      * @param choiceKeys an array of strings used to construct the resource
1176      * names for the choices.
1177      * @param editable True if the choice component should allow freeform
1178      * editing of the response.
1179      * @return a choice box with the attributes indicated by the parameters
1180      * @see #createChoice(String,String[])
1181      */
1182     public JComboBox<String> createChoice(final String uiKey, final String[] choiceKeys, boolean editable) {
1183         // create a cache of the presentation string, for use when
1184         // rendering, but otherwise, let the JComboBox work in terms of the
1185         // choiceKeys
1186         final String[] choices = new String[choiceKeys.length];
1187         for (int i = 0; i < choices.length; i++)
1188             choices[i] = getI18NString(uiKey + "." + choiceKeys[i] + ".chc");
1189 
1190         JComboBox<String> choice = new JComboBox<>(choiceKeys);
1191         choice.setName(uiKey);
1192         setToolTip(choice, uiKey);
1193         setAccessibleName(choice, uiKey);
1194 
1195         choice.setEditable(editable);
1196         if (editable) {
1197             Component editComp = choice.getEditor().getEditorComponent();
1198             if (editComp instanceof Accessible) {
1199                 if (editComp.getName() == null)
1200                     editComp.setName(uiKey + ".ed");
1201                 AccessibleContext ac = choice.getAccessibleContext();
1202                 AccessibleContext ed_ac = editComp.getAccessibleContext();
1203                 ed_ac.setAccessibleName(ac.getAccessibleName());
1204                 ed_ac.setAccessibleDescription(ac.getAccessibleDescription());
1205             }
1206         }
1207 
1208         choice.setRenderer(new DefaultListCellRenderer() {
1209             public Component getListCellRendererComponent(JList<?> list, Object o, int index,
1210                                 boolean isSelected, boolean cellHasFocus) {
1211                 Object c = o;
1212                 for (int i = 0; i < choiceKeys.length; i++) {
1213                     if (choiceKeys[i] == o) {
1214                         c = choices[i];
1215                         break;
1216                     }
1217                 }
1218                 return super.getListCellRendererComponent(list, c, index, isSelected, cellHasFocus);
1219             }
1220         });
1221 
1222         return choice;
1223     }
1224 
1225     /**
1226      * Create an empty choice item, using a resource to specify the tool tip. <br>
1227      * The resource used is:
1228      * <table>
1229      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the choice item
1230      * </table>
1231      * In addition, the name of the choice is set to <i>uiKey</i>.
1232      * @param uiKey the base name of the resources to be used for the menu
1233      * @return the choice component that was created
1234      */
1235     public <E> JComboBox<E> createChoice(String uiKey) {
1236         return createChoice(uiKey, false);
1237     }
1238 
1239     /**
1240      * Same as single parameter version, except you can select a
1241      * component that allows freeform editing of the user's response.
1242      * @param uiKey the base name of the resources to be used for the menu
1243      * @param editable True if the user should be allowed to edit the
1244      * response.
1245      * @return the choice component that was created
1246      * @see #createChoice(String)
1247      */
1248     public <E> JComboBox<E> createChoice(String uiKey, boolean editable) {
1249         return createChoice(uiKey, editable, null);
1250     }
1251 
1252     /**
1253      * Same as the one parameter version, except a label can be
1254      * associated with this component.  This is to support accessibility.
1255      * @param uiKey the base name of the resources to be used for the menu
1256      * @param label Label to associate with this component
1257      * @return the choice component that was created
1258      * @see #createChoice(String)
1259      * @see javax.swing.JLabel#setLabelFor
1260      */
1261     public <E> JComboBox<E> createChoice(String uiKey, JLabel label) {
1262         return createChoice(uiKey, false, label);
1263     }
1264 
1265     /**
1266      * Combination of the two parameter methods, allowing you to select
1267      * a mutable response and associate a label.
1268      * @param uiKey the base name of the resources to be used for the menu
1269      * @param editable True if the user should be allowed to edit the
1270      * response.
1271      * @param label Label to associate with this component
1272      * @return a choice box with the attributes indicated by the parameters
1273      * @see #createChoice(String,JLabel)
1274      * @see #createChoice(String,boolean)
1275      * @see #createChoice(String)
1276      * @see javax.swing.JLabel#setLabelFor
1277      */
1278     public <E> JComboBox<E> createChoice(String uiKey, boolean editable, JLabel label) {
1279         JComboBox<E> choice = new JComboBox<>();
1280         choice.setName(uiKey);
1281         setToolTip(choice, uiKey);
1282 
1283         if (label != null)
1284             label.setLabelFor(choice);
1285         else
1286             setAccessibleName(choice, uiKey);
1287 
1288         choice.setEditable(editable);
1289         if (editable) {
1290             Component editComp = choice.getEditor().getEditorComponent();
1291             if (editComp instanceof Accessible) {
1292                 if (editComp.getName() == null)
1293                     editComp.setName(uiKey + ".ed");
1294                 AccessibleContext ac = choice.getAccessibleContext();
1295                 AccessibleContext ed_ac = editComp.getAccessibleContext();
1296                 ed_ac.setAccessibleName(ac.getAccessibleName());
1297                 ed_ac.setAccessibleDescription(ac.getAccessibleDescription());
1298             }
1299         }
1300 
1301         return choice;
1302     }
1303 
1304     /**
1305      * Create an choice item containing literal choices,
1306      * and using a resource to specify the tool tip.
1307      * The choices appear as given: for example, this method might be used to
1308      * create a choice item containing a set of filenames from which to choose. <br>
1309      * Note that if the choices are strings, they should probably be localized, and
1310      * if they are otherwise should probably be shown to the user using a renderer
1311      * which produces localized output.
1312      * The resource used is:
1313      * <table>
1314      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the choice item
1315      * </table>
1316      * In addition, the name of the choice is set to <i>uiKey</i>.
1317      * @param uiKey the base name of the resources to be used for the menu
1318      * @param choices the choices to appear in the choice item
1319      * @return the choice item that was created
1320      * @see #createChoice
1321      */
1322     public <E> JComboBox<E> createLiteralChoice(String uiKey, E[] choices) {
1323         JComboBox<E> choice = new JComboBox<>(choices);
1324         choice.setName(uiKey);
1325         setToolTip(choice, uiKey);
1326         return choice;
1327     }
1328 
1329     //----------------------------------------------------------------------------
1330     //
1331     // icons, images etc
1332 
1333     /**
1334      * Create an icon, using a resource to specify the image. <br>
1335      * The resource used is:
1336      * <table>
1337      * <tr><td><i>uiKey</i>.icon  <td>the name of a resource containing the image
1338      * </table>
1339      * @param uiKey the base name of the resource to be used
1340      * @return the icon that was created
1341      * @throws  MissingResourceException if the image resource cannot be found
1342      * @see #createIconButton
1343      */
1344     public Icon createIcon(String uiKey) {
1345         return new ImageIcon(getIconURL(uiKey));
1346     }
1347 
1348     /**
1349      * Get the resource URL for an icon specified in a resource bundle. <br>
1350      * The resource used is:
1351      * <table>
1352      * <tr><td><i>uiKey</i>.icon  <td>the name of a resource containing the image
1353      * </table>
1354      * @param uiKey the base name of the resource to be used
1355      * @return the URL for the resource obtained from the resource bundle
1356      * @throws  MissingResourceException if the image resource cannot be found
1357      */
1358     public URL getIconURL(String uiKey) {
1359         String r = getI18NString(uiKey + ".icon");
1360         URL url = clientClass.getResource(r);
1361         if (url == null)
1362             throw new MissingResourceException(r, clientClass.getName(), r);
1363         return url;
1364     }
1365 
1366     /**
1367      * Create a label containing an icon, using a resource to specify the
1368      * icon image. <br>
1369      * The resource used is:
1370      * <table>
1371      * <tr><td><i>uiKey</i>.icon <td>the name of the resource for the icon image
1372      * </table>
1373      * @param uiKey the base name of the resource to be used
1374      * @return the image that was created
1375      * @throws  MissingResourceException if the image resource cannot be found
1376      * @see #createLabel
1377      */
1378     public JLabel createIconLabel(String uiKey) {
1379         return new JLabel(createIcon(uiKey));
1380     }
1381 
1382     /**
1383      * Create an image from a named resource.
1384      * @param r The resource containing the image data.
1385      * @return the image that was created
1386      * @throws  MissingResourceException if the image resource cannot be found
1387      */
1388     public Image createImage(String r) {
1389         URL url = getClass().getResource(r);
1390         if (url == null)
1391             throw new MissingResourceException(r, clientClass.getName(), r);
1392         return Toolkit.getDefaultToolkit().getImage(url);
1393     }
1394 
1395     //----------------------------------------------------------------------------
1396     //
1397     // labels
1398 
1399     /**
1400      * Create a label, using a resource to specify the text. <br>
1401      * The resource used is:
1402      * <table>
1403      * <tr><td><i>uiKey</i>.lbl  <td>the text for the label
1404      * </table>
1405      * @param uiKey the base name of the resource to be used
1406      * @return the label that was created
1407      * @see #createIconLabel
1408      */
1409     public JLabel createLabel(String uiKey) {
1410         return createLabel(uiKey, false);
1411     }
1412 
1413     /**
1414      * Create a label, using a resource to specify the text and an optional mnemonic.<br>
1415      * The resource used is:
1416      * <table>
1417      * <tr><td><i>uiKey</i>.lbl  <td>the text for the label
1418      * <tr><td><i>uiKey</i>.tip  <td>the tooltip text for the label
1419      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the label
1420      * </table>
1421      * @param uiKey the base name of the resource to be used
1422      * @param need508 whether or not a mnemonic and tooltip should be set for this label
1423      * @return the label that was created
1424      * @see #createIconLabel
1425      */
1426     public JLabel createLabel(String uiKey, boolean need508) {
1427         JLabel l = new JLabel(getI18NString(uiKey + ".lbl"));
1428         l.setName(uiKey);
1429         if (need508) {
1430             setToolTip(l, uiKey);
1431             l.setDisplayedMnemonic(getI18NMnemonic(uiKey + ".mne"));
1432         }
1433         return l;
1434     }
1435 
1436 
1437     //----------------------------------------------------------------------------
1438     //
1439     // lists
1440 
1441     /**
1442      * Create an input text field, using a resource to specify the tool tip.  <br>
1443      * The resource used is:
1444      * <table>
1445      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
1446      * </table>
1447 
1448 
1449     /**
1450      * Create an empty list component. <br>
1451      * Note: list components do not currently support tool tips.
1452      * When they do, this method will use a resource to specify the tool tip.
1453      * The resources used are:
1454      * <table>
1455      * <tr><td><i>uiKey</i>.name  <td>the accessible name of the list
1456      * <tr><td><i>uiKey</i>.desc  <td>the accessible description of the list
1457      * </table>
1458      * @param uiKey the base name of the resource to be used (currently ignored)
1459      * @return the list that was created
1460      */
1461     public <E> JList<E> createList(String uiKey) {
1462         JList<E> list = new JList<>();
1463         list.setName(uiKey);
1464         setAccessibleInfo(list, uiKey);
1465         return list;
1466     }
1467 
1468     /**
1469      * Create a list component with a given data model. <br>
1470      * Note: list components do not currently support tool tips.
1471      * When they do, this method will use a resource to specify the tool tip.
1472      * The resources used are:
1473      * <table>
1474      * <tr><td><i>uiKey</i>.name  <td>the accessible name of the list
1475      * <tr><td><i>uiKey</i>.desc  <td>the accessible description of the list
1476      * </table>
1477      * @param uiKey the base name of the resource to be used (currently ignored)
1478      * @param model the data model for this list
1479      * @return the list that was created
1480      */
1481     public <E> JList<E> createList(String uiKey, ListModel<E> model) {
1482         JList<E> list = new JList<>(model);
1483         list.setName(uiKey);
1484         setAccessibleInfo(list, uiKey);
1485         return list;
1486     }
1487 
1488     //----------------------------------------------------------------------------
1489     //
1490     // menus
1491 
1492     /**
1493      * Create an empty menu bar, using resources to specify the accessible info.<br>
1494      * The resources used are:
1495      * <table>
1496      * <tr><td><i>uiKey</i>.name <td>the accessible name text
1497      * <tr><td><i>uiKey</i>.desc <td>accessible description text
1498      * </table>
1499      * @param uiKey the base name of the resource to be used
1500      * @return the menu bar that was created
1501      */
1502     public JMenuBar createMenuBar(String uiKey) {
1503         JMenuBar mb = new JMenuBar();
1504         mb.setName(uiKey);
1505         setAccessibleInfo(mb, uiKey);
1506         return mb;
1507     }
1508 
1509     /**
1510      * Create an empty menu, using resources to specify the name and mnemonic. <br>
1511      * The resources used are:
1512      * <table>
1513      * <tr><td><i>uiKey</i>.menu  <td>the display name of the menu
1514      * <tr><td><i>uiKey</i>.mne  <td>the single character mnemonic for the menu
1515      * <tr><td><i>uiKey</i>.desc <td>accessible description text
1516      * </table>
1517      * @param uiKey the base name of the resource to be used
1518      * @return the menu that was created
1519      * @see #createPopupMenu
1520      */
1521     public JMenu createMenu(String uiKey) {
1522         JMenu m = new JMenu();
1523         initMenu(m, uiKey);
1524         return m;
1525     }
1526 
1527     /**
1528      * Initialize an empty menu, using resources to specify the name and mnemonic. <br>
1529      * The resources used are:
1530      * <table>
1531      * <tr><td><i>uiKey</i>.menu  <td>the display name of the menu
1532      * <tr><td><i>uiKey</i>.mne  <td>the single character mnemonic for the menu
1533      * <tr><td><i>uiKey</i>.desc <td>accessible description text
1534      * </table>
1535      * @param m the menu the be initialized
1536      * @param uiKey the base name of the resource to be used
1537      * @see #createPopupMenu
1538      */
1539     public void initMenu(JMenu m, String uiKey) {
1540         m.setName(uiKey);
1541         m.setText(getI18NString(uiKey + ".menu"));
1542         setMnemonic(m, uiKey);
1543         setAccessibleDescription(m, uiKey);
1544     }
1545 
1546     /**
1547      * Create a menu, using actions to specify the menu items,
1548      * and using resources to specify the name and mnemonic. <br>
1549      * The resources used are:
1550      * <table>
1551      * <tr><td><i>uiKey</i>.menu  <td>the display name of the menu
1552      * <tr><td><i>uiKey</i>.mne  <td>the single character mnemonic for the menu
1553      * </table>
1554      * @param uiKey the base name of the resources to be used
1555      * @param actions the actions from which to create the menu items;
1556      *  use null in the array to indicate if and where a separator is required
1557      * @return the menu that was created
1558      * @see #createMenuItem(Action)
1559      */
1560     public JMenu createMenu(String uiKey, Action[] actions) {
1561         JMenu m = createMenu(uiKey);
1562         for (int i = 0; i < actions.length; i++) {
1563             Action action = actions[i];
1564             if (action == null)
1565                 m.addSeparator();
1566             else
1567                 m.add(createMenuItem(action));
1568         }
1569         return m;
1570     }
1571 
1572     /**
1573      * Create a menu using resources and an action listener to specify
1574      * the menu items, and using resources to specify the name and mnemonic. <br>
1575      * The resources used are:
1576      * <table>
1577      * <tr><td><i>uiKey</i>.menu  <td>the display name of the menu
1578      * <tr><td><i>uiKey</i>.mne  <td>the single character mnemonic for the menu
1579      * <tr><td><i>uiKey</i>.<i>actions<sub>i</sub></i>.mit  <td>the text for the menu item, for 0 &lt;= i &lt; choiceKeys.length
1580      * <tr><td><i>uiKey</i>.<i>actions<sub>i</sub></i>.mne  <td>the single character mnemonic for the menu item, for 0 &lt;= i &lt; choiceKeys.length
1581      * </table>
1582      * @param uiKey the base name of the resources to be used
1583      * @param actions the qualifying names for the resources for the
1584      *  individual menu items; use null in the array to indicate if
1585      *  and where a separator is required
1586      * @param l the action listener to be used for each menu item
1587      * @return the menu that was created
1588      * @see #createMenuItem(String, String, ActionListener)
1589      */
1590     public JMenu createMenu(String uiKey, String[] actions, ActionListener l) {
1591         JMenu m = new JMenu();
1592         initMenu(m, uiKey, actions, l);
1593         return m;
1594     }
1595 
1596     /**
1597      * Initialize a menu using resources and an action listener to specify
1598      * the menu items, and using resources to specify the name and mnemonic. <br>
1599      * The resources used are:
1600      * <table>
1601      * <tr><td><i>uiKey</i>.menu  <td>the display name of the menu
1602      * <tr><td><i>uiKey</i>.mne  <td>the single character mnemonic for the menu
1603      * <tr><td><i>uiKey</i>.<i>actions<sub>i</sub></i>.mit  <td>the text for the menu item, for 0 &lt;= i &lt; choiceKeys.length
1604      * <tr><td><i>uiKey</i>.<i>actions<sub>i</sub></i>.mne  <td>the single character mnemonic for the menu item, for 0 &lt;= i &lt; choiceKeys.length
1605      * </table>
1606      * @param m the menu the be initialized
1607      * @param uiKey the base name of the resources to be used
1608      * @param actions the qualifying names for the resources for the
1609      *  individual menu items; use null in the array to indicate if
1610      *  and where a separator is required
1611      * @param l the action listener to be used for each menu item
1612      * @see #createMenuItem(String, String, ActionListener)
1613      */
1614     public void initMenu(JMenu m, String uiKey, String[] actions, ActionListener l) {
1615         initMenu(m, uiKey);
1616         for (int i = 0; i < actions.length; i++) {
1617             String action = actions[i];
1618             if (action == null)
1619                 m.addSeparator();
1620             else
1621                 m.add(createMenuItem(uiKey, action, l));
1622         }
1623     }
1624 
1625     /**
1626      * Create an empty popup menu.
1627      * @param uiKey the base name of the resource to be used (currently ignored)
1628      * @return the popup menu that was created
1629      * @see #createMenu
1630      */
1631     public JPopupMenu createPopupMenu(String uiKey) {
1632         return new JPopupMenu(/*getI18NString(uiKey + ".pop")*/);
1633     }
1634 
1635     /**
1636      * Create an popup menu.
1637      * @param uiKey the base name of the resource to be used
1638      * @param actions the qualifying names for the resources for the
1639      *  individual menu items; use null in the array to indicate if
1640      *  and where a separator is required
1641      * @param l the action listener to be used for each menu item
1642      * @return the popup menu that was created
1643      * @see #createMenu
1644      */
1645     public JPopupMenu createPopupMenu(String uiKey, String[] actions, ActionListener l) {
1646         JPopupMenu m = createPopupMenu(uiKey);
1647         for (int i = 0; i < actions.length; i++) {
1648             String action = actions[i];
1649             if (action == null)
1650                 m.addSeparator();
1651             else
1652                 m.add(createMenuItem(uiKey, action, l));
1653         }
1654         return m;
1655     }
1656 
1657     //----------------------------------------------------------------------------
1658     //
1659     // menu items
1660 
1661     /**
1662      * Create a menu item for an action.
1663      * The name of the item is set to the action name.
1664      * @param action from which to create the menu item
1665      * @return the menu item that was created
1666      * @see #createMenu(String, Action[])
1667      */
1668     public JMenuItem createMenuItem(Action action) {
1669         JMenuItem item = new JMenuItem(action);
1670         item.setName((String)(action.getValue(Action.NAME)));
1671         // could (should?) ensure everything is set correctly
1672         return item;
1673     }
1674 
1675     /**
1676      * Create a menu item, using resources to specify the text and mnemonic. <br>
1677      * The resources used are:
1678      * <table>
1679      * <tr><td><i>uiKey</i>.<i>action</i>.mit  <td>the text for the menu item
1680      * <tr><td><i>uiKey</i>.<i>action</i>.mne  <td>the single character mnemonic for the menu item
1681      * </table>
1682      * @param uiKey the base name of the resources to be used
1683      * @param action the qualifying name for the resources for the menu item
1684      * @param l the action listener for the menu item
1685      * @return the menu item that was created
1686      * @see #createMenu(String, String[], ActionListener)
1687      */
1688     public JMenuItem createMenuItem(String uiKey, String action, ActionListener l) {
1689         JMenuItem item = new JMenuItem(getI18NString(uiKey + "." + action + ".mit"));
1690         item.setActionCommand(action);
1691         item.addActionListener(l);
1692         item.setName(action);
1693         setMnemonic(item, uiKey + "." + action);
1694         return item;
1695     }
1696 
1697     /**
1698      * Create a check box menu item, using resources to specify the
1699      * name and the tool tip. <br>
1700      * The resources used are:
1701      * <table>
1702      * <tr><td><i>uiKey</i>.<i>name</i>.ckb  <td>the name for the menu item
1703      * <tr><td><i>uiKey</i>.<i>name</i>.tip  <td>the tool tip for the menu item
1704      * </table>
1705      * In addition, the name of the check box is set to <i>uiKey</i>.
1706      * @param uiKey the base name of the resources to be used
1707      * @param name a qualifying name for the resources used for this menu item
1708      * @param state the initial state of the check box
1709      * @return the check box that was created
1710      */
1711     public JCheckBoxMenuItem createCheckBoxMenuItem(String uiKey, String name, boolean state) {
1712         String uiKey_name = uiKey + "." + name;
1713         String ckbKey = uiKey_name + ".ckb";
1714         JCheckBoxMenuItem b = new JCheckBoxMenuItem(getI18NString(ckbKey), state);
1715         b.setName(uiKey_name);
1716         setMnemonic(b, uiKey_name);
1717         setToolTip(b, uiKey_name);
1718         return b;
1719     }
1720 
1721     /**
1722      * Create a Help menu item, that will display a specific help topic when pressed,
1723      * using resources to specify the name and mnemonic for the item.  <br>
1724      * The resource used is:
1725      * <table>
1726      * <tr><td><i>uiKey</i>.mit  <td>the text for the menu item
1727      * <tr><td><i>uiKey</i>.mne  <td>the mnemonic for the menu item
1728      * </table>
1729      * In addition, the name of the choice is set to <i>uiKey</i>.
1730      * @param uiKey the base name of the resources to be used
1731      * @param helpID the help ID for the help topic to be displayed when the
1732      * button is pressed
1733      * @return the button that was created
1734      * @see #createButton
1735      */
1736     public JMenuItem createHelpMenuItem(String uiKey, final String helpID) {
1737         JMenuItem mi = new JMenuItem(getI18NString(uiKey + ".mit"));
1738         setMnemonic(mi, uiKey);
1739         mi.addActionListener(new ActionListener() {
1740             @Override
1741             public void actionPerformed(ActionEvent e) {
1742                 if (helpBroker != null) {
1743                     helpBroker.displayCurrentID(helpID);
1744                 }
1745             }
1746         });
1747 
1748         return mi;
1749     }
1750 
1751     /**
1752      * Create a menu item for a literal string and a specified listener.
1753      * No mnemonic key nor descriptive action is added.
1754      * @param literal the text for the menu item
1755      * @param l the action listener to add to the menu item
1756      * @return the menu item that was created
1757      */
1758     public JMenuItem createLiteralMenuItem(String literal, ActionListener l) {
1759         JMenuItem item = new JMenuItem(literal);
1760         item.addActionListener(l);
1761         return item;
1762     }
1763 
1764     /**
1765      * Create a check box menu item, using resources to specify the
1766      * name and the tool tip. <br>
1767      * The resources used are:
1768      * <table>
1769      * <tr><td><i>uiKey</i>.<i>name</i>.ckb  <td>the name for the menu item
1770      * <tr><td><i>uiKey</i>.<i>name</i>.tip  <td>the tool tip for the menu item
1771      * </table>
1772      * In addition, the name of the radio button is set to <i>uiKey</i>.
1773      * @param uiKey the base name of the resources to be used
1774      * @param name a qualifying name for the resources used for this menu item
1775      * @return the check box that was created
1776      */
1777     public JRadioButtonMenuItem createRadioButtonMenuItem(String uiKey, String name) {
1778         String uiKey_name = uiKey + "." + name;
1779         String radKey = uiKey_name + ".rad";
1780         JRadioButtonMenuItem b = new JRadioButtonMenuItem(getI18NString(radKey));
1781         b.setName(uiKey_name);
1782         setMnemonic(b, uiKey_name);
1783         setToolTip(b, uiKey_name);
1784         return b;
1785     }
1786 
1787     //----------------------------------------------------------------------------
1788     //
1789     // scrollpane
1790 
1791     /**
1792      * Surround a component in a scroll pane.
1793      * The name of the scroll pane component is set to <code>c.getName()</code>
1794      * plus the <i>.sp</i> suffix.
1795      * @param c The component to put into the scroll pane.
1796      * @return a scroll pane component with the given component inside
1797      */
1798     public JScrollPane createScrollPane(JComponent c) {
1799         JScrollPane sp = new JScrollPane(c);
1800         sp.setName(c.getName() == null ? "sp" : c.getName() + ".sp");
1801         sp.setFocusable(false);
1802         return sp;
1803     }
1804 
1805     /**
1806      * Same as the single argument version, with options for altering
1807      * the scrollbar appearance policy.
1808      * @param c The component to put into the scroll pane.
1809      * @param vsp vertical scrollbar policy setting
1810      * @param hsp horizontal scrollbar policy setting
1811      * @return a scroll pane component with the given component inside
1812      * @see javax.swing.ScrollPaneConstants
1813      * @see javax.swing.JScrollPane
1814      */
1815     public JScrollPane createScrollPane(JComponent c, int vsp, int hsp) {
1816         JScrollPane sp = new JScrollPane(c, vsp, hsp);
1817         sp.setName(c.getName() == null ? "sp" : c.getName() + ".sp");
1818         sp.setFocusable(false);
1819         return sp;
1820     }
1821 
1822     //----------------------------------------------------------------------------
1823     //
1824     // slider
1825 
1826     /**
1827      * Create a slider, using resources to specify the the tool tip. <br>
1828      * The resource used is:
1829      * <table>
1830      * <tr><td><i>uiKey</i>.<i>name</i>.tip  <td>the tool tip for the menu item
1831      * </table>
1832      * @param uiKey the base name of the resources to be used
1833      * @param min the minimum value for the slider
1834      * @param max the maximum value for the slider
1835      * @param value the initial value for the slider
1836      * @return the slider that was created
1837      */
1838     public JSlider createSlider(String uiKey, int min, int max, int value) {
1839         JSlider s = new JSlider(min, max, value);
1840         setToolTip(s, uiKey);
1841         return s;
1842     }
1843 
1844     //----------------------------------------------------------------------------
1845     //
1846     // split pane
1847 
1848     /**
1849      * Create an empty split pane with the given orientation.
1850      * @param orient The split's orientation.
1851      * @return The empty split pane component.
1852      * @see javax.swing.JSplitPane#VERTICAL_SPLIT
1853      * @see javax.swing.JSplitPane#HORIZONTAL_SPLIT
1854      */
1855     public JSplitPane createSplitPane(int orient) {
1856         JSplitPane sp = new JSplitPane(orient);
1857         sp.setName("split");
1858         setSplitPaneInfo(sp);
1859         return sp;
1860     }
1861 
1862     /**
1863      * Create an empty split pane with the given components inside.
1864      * @param orient The split's orientation.
1865      * @param c1 first component (left)
1866      * @param c2 first component (right)
1867      * @return The populated split pane component.
1868      * @see javax.swing.JSplitPane
1869      * @see javax.swing.JSplitPane#VERTICAL_SPLIT
1870      * @see javax.swing.JSplitPane#HORIZONTAL_SPLIT
1871      */
1872     public JSplitPane createSplitPane(int orient, Component c1, Component c2) {
1873         JSplitPane sp = new JSplitPane(orient, c1, c2);
1874         sp.setName("split");
1875         setSplitPaneInfo(sp);
1876         return sp;
1877     }
1878 
1879     private void setSplitPaneInfo(JSplitPane sp) {
1880         // set a11y info manually using local bundle
1881         AccessibleContext ac = sp.getAccessibleContext();
1882         if (sp.getOrientation() == JSplitPane.HORIZONTAL_SPLIT) {
1883             ac.setAccessibleName(local_i18n.getString("uif.sp.hor.name"));
1884             ac.setAccessibleDescription(local_i18n.getString("uif.sp.hor.desc"));
1885         }
1886         else {
1887             ac.setAccessibleName(local_i18n.getString("uif.sp.vert.name"));
1888             ac.setAccessibleDescription(local_i18n.getString("uif.sp.vert.desc"));
1889         }
1890     }
1891 
1892     //----------------------------------------------------------------------------
1893     //
1894     // spinners - not accessible as of JDK 1.5, so it's commented out here!
1895 
1896     /**
1897      * Create a spinner.
1898      * @param uiKey the base name of the resources to be used
1899      * @return a spinner component
1900      * The resources used are:
1901      * <table>
1902      * <tr><td><i>uiKey</i>.<code>name</code><td> the accessible name for the tab pane.
1903      *          Where <code>name</code> is the literal string "name".
1904      * <tr><td><i>uiKey</i>.<code>tip</code><td> the accessible name for the tab pane.
1905      *          Where <code>tip</code> is the literal string "tip".
1906      * </table>
1907      * The tooltip will automatically be transferred to the pane's accessible
1908      * description.  Use <code>setAccessibleDescription()</code> to set it
1909      * independently.
1910     public JSpinner createSpinner(String uiKey, SpinnerModel model) {
1911         JSpinner s = new JSpinner(model);
1912         s.setName(uiKey);
1913         setAccessibleName(s, uiKey);
1914         setToolTip(s, uiKey);
1915         return s;
1916     }
1917      */
1918 
1919 
1920     //----------------------------------------------------------------------------
1921     //
1922     // tabbed paned
1923 
1924     /**
1925      * Create an empty tabbed pane.
1926      * @param uiKey the base name of the resources to be used
1927      * @return an empty (no tabs) tabbed pane
1928      * The resources used are:
1929      * <table>
1930      * <tr><td><i>uiKey</i>.<code>name</code><td> the accessible name for the tab pane.
1931      *          Where <code>name</code> is the literal string "name".
1932      * <tr><td><i>uiKey</i>.<code>tip</code><td> the accessible name for the tab pane.
1933      *          Where <code>tip</code> is the literal string "tip".
1934      * </table>
1935      * The tooltip will automatically be transferred to the pane's accessible
1936      * description.  Use <code>setAccessibleDescription()</code> to set it
1937      * independently.
1938      */
1939     public JTabbedPane createTabbedPane(String uiKey) {
1940         JTabbedPane p = new JTabbedPane();
1941         p.setName(uiKey);
1942         setAccessibleName(p, uiKey);
1943         setToolTip(p, uiKey);
1944         return p;
1945     }
1946 
1947     /**
1948      * Create a tabbed pane with a given set of component panes,
1949      * using resources to determine the name and tool tip for each tab. <br>
1950      * The resources used are:
1951      * <table>
1952      * <tr><td><i>uiKey</i>.<i>name<sub>i</sub></i>.tab  <td>the display name for the tab,
1953      *          where <i>name<sub>i</sub></i> is the component name for children[i]
1954      * <tr><td><i>uiKey</i>.<i>name<sub>i</sub></i>.tip  <td>the tool tip for the tab,
1955      *          where <i>name<sub>i</sub></i> is the component name for children[i]
1956      * <tr><td><i>uiKey</i>.<code>name</code><td> the accessible name for the tab pane.
1957      *          Where <code>name</code> is the literal string "name".
1958      * <tr><td><i>uiKey</i>.<code>tip</code><td> the accessible name for the tab pane.
1959      *          Where <code>tip</code> is the literal string "tip".
1960      * </table>
1961      * The tooltip will automatically be transferred to the pane's accessible
1962      * description.  Use <code>setAccessibleDescription()</code> to set it
1963      * independently.
1964      * @param uiKey the base name of the resources to be used
1965      * @param children an array of components to be added into the tabbed pane
1966      * @return the tabbed pane that was created
1967      * @see #setAccessibleDescription(Component,String)
1968      * @see #setAccessibleName(Component,String)
1969      * @see #setToolTip(JComponent,String)
1970      */
1971     public JTabbedPane createTabbedPane(String uiKey, JComponent[] children) {
1972         JTabbedPane p = new JTabbedPane();
1973         p.setName(uiKey);
1974         setAccessibleName(p, uiKey);
1975         for (int i = 0; i < children.length; i++) {
1976             JComponent child = children[i];
1977             addTab(p, uiKey + "." + child.getName(), child);
1978         }
1979         setToolTip(p, uiKey);
1980         return p;
1981     }
1982 
1983     /**
1984      * Add a component to a tabbed pane, using resources to specify
1985      * the name and the tool tip for the tab. <br>
1986      * The resources used are:
1987      * <table>
1988      * <tr><td><i>uiKey</i>.tab  <td>the name for the tab
1989      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the tab
1990      * </table>
1991      * @param tPane the tabbed pane to which to add the component
1992      * @param uiKey the base name of the resources to be used
1993      * @param comp the component to be added
1994      */
1995     public void addTab(JTabbedPane tPane, String uiKey, JComponent comp) {
1996         String name = getI18NString(uiKey + ".tab");
1997         String tip = getI18NString(uiKey + ".tip");
1998         tPane.addTab(name, null, comp, tip);
1999 
2000     }
2001 
2002     //----------------------------------------------------------------------------
2003     //
2004     // tables
2005 
2006     /**
2007      * Create a table with a given data model.
2008      * Resources used:
2009      * <table>
2010      * <tr><td><i>uiKey</i>.<code>name</code><td> the accessible name for the tab pane.
2011      *          Where <code>name</code> is the literal string "name".
2012      * <tr><td><i>uiKey</i>.<code>tip</code><td> the accessible name for the tab pane.
2013      *          Where <code>tip</code> is the literal string "tip".
2014      * </table>
2015      * The tooltip will automatically be transferred to the pane's accessible
2016      * description.  Use <code>setAccessibleDescription()</code> to set it
2017      * independently.
2018      * @param uiKey the base name of the resources to be used (currently ignored)
2019      * @param model the data model for the table
2020      * @return the table that was created
2021      * @see #setAccessibleDescription(Component,String)
2022      * @see #setAccessibleName(Component,String)
2023      * @see #setToolTip(JComponent,String)
2024      */
2025     public JTable createTable(String uiKey, TableModel model) {
2026         JTable tbl = new JTable(model);
2027         setAccessibleName(tbl, uiKey);
2028         setToolTip(tbl, uiKey);
2029         return tbl;
2030     }
2031 
2032     //----------------------------------------------------------------------------
2033     //
2034     // text fields, text areas etc
2035 
2036     /**
2037      * Create a text field for use as a heading, using a resource to specify
2038      * the heading. <br>
2039      * The resource used is:
2040      * <table>
2041      * <tr><td><i>uiKey</i>.txt  <td>the text for the heading
2042      * </table>
2043      * In addition, the name of the output field is set to <i>uiKey</i>.
2044      * @param uiKey the base name of the resource to be used
2045      * @return the text field that was created
2046      */
2047     public JTextField createHeading(String uiKey) {
2048         String value = getI18NString(uiKey + ".txt");
2049         JTextField tf = new JTextField(value, value.length());
2050         tf.setName(uiKey);
2051         tf.setEditable(false);
2052         tf.setFont(tf.getFont().deriveFont(Font.BOLD));
2053         tf.setBorder(BorderFactory.createEmptyBorder());
2054         tf.setBackground(Colors.TRANSPARENT.color);
2055         tf.setOpaque(false);
2056         setAccessibleDescription(tf, uiKey);
2057         setAccessibleName(tf, uiKey);
2058         return tf;
2059     }
2060 
2061     /**
2062      * Create an input text field, using a resource to specify the tool tip.  <br>
2063      * The resource used is:
2064      * <table>
2065      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2066      * </table>
2067      * In addition, the name of the input field is set to <i>uiKey</i>.
2068      * By default, the input field is 10 characters wide.
2069      * @param uiKey the base name of the resource to be used
2070      * @return the input field that was created
2071      */
2072     public JTextField createInputField(String uiKey) {
2073         return createInputField(uiKey, null);
2074     }
2075 
2076     /**
2077      * Create an input text field, using a resource to specify the tool tip.  <br>
2078      * The resource used is:
2079      * <table>
2080      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2081      * </table>
2082      * In addition, the name of the input field is set to <i>uiKey</i>.
2083      * By default, the input field is 10 characters wide.
2084      * @param uiKey the base name of the resource to be used
2085      * @param label the label to associate with this component
2086      * @return the input field that was created
2087      */
2088     public JTextField createInputField(String uiKey, JLabel label) {
2089         return createInputField(uiKey, 10, label);
2090     }
2091 
2092     /**
2093      * Create an input text field with a specified number of columns,
2094      * using a resource to specify the tool tip.  <br>
2095      * The resource used is:
2096      * <table>
2097      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2098      * </table>
2099      * In addition, the name of the input field is set to <i>uiKey</i>.
2100      * @param uiKey the base name of the resource to be used
2101      * @param cols the default width of the field, in characters
2102      * @return the input field that was created
2103      * @see #createOutputField
2104      */
2105     public JTextField createInputField(String uiKey, int cols) {
2106         return createInputField(uiKey, cols, null);
2107     }
2108 
2109     /**
2110      * Create an input text field with a specified number of columns,
2111      * using a resource to specify the tool tip.  <br>
2112      * The resource used is:
2113      * <table>
2114      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2115      * </table>
2116      * In addition, the name of the input field is set to <i>uiKey</i>.
2117      * @param uiKey the base name of the resource to be used
2118      * @param cols the default width of the field, in characters
2119      * @param label the label to associate with this component
2120      * @return the input field that was created
2121      * @see #createOutputField
2122      */
2123     public JTextField createInputField(String uiKey, int cols, JLabel label) {
2124         JTextField tf = new JTextField("", cols) {
2125             public Dimension getMinimumSize() {
2126                 return getPreferredSize();
2127             }
2128         };
2129 
2130         if (label != null)
2131             label.setLabelFor(tf);
2132         else {
2133             // this should be setAccessibleName(tf, uiKey); but that will break too much code
2134             tf.setName(uiKey);
2135             //setAccessibleName(tf, uiKey);
2136         }
2137 
2138         setToolTip(tf, uiKey);
2139         return tf;
2140     }
2141 
2142     /**
2143      * Create a message area, using a resource to specify the content.
2144      * The message area will be transparent, uneditable, and word-wrapped. <br>
2145      * The resource used is:
2146      * <table>
2147      * <tr><td><i>uiKey</i>.txt  <td>the text for the message area
2148      * </table>
2149      * @param uiKey the name of the resource to be used
2150      * @return the message area that was created
2151      */
2152     public JTextArea createMessageArea(String uiKey) {
2153         return createLocalizedMessageArea(uiKey, getI18NString(uiKey + ".txt"), true);
2154     }
2155 
2156     /**
2157      * Create a message area, using a resource to specify the content.
2158      * The message area will be transparent, uneditable, and word-wrapped. <br>
2159      * The resource used is:
2160      * <table>
2161      * <tr><td><i>uiKey</i>.txt  <td>the text for the message area
2162      * <tr><td><i>uiKey</i>.name  <td>accessible name
2163      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
2164      * </table>
2165      * @param uiKey the name of the resource to be used
2166      * @param arg an argument to be formatted into the content using
2167      * {@link java.text.MessageFormat#format}
2168      * @return the message area that was created
2169      */
2170     public JTextArea createMessageArea(String uiKey, Object arg) {
2171         return createLocalizedMessageArea(uiKey, getI18NString(uiKey + ".txt", arg), true);
2172     }
2173 
2174 
2175     /**
2176      * Create a message area, using a resource to specify the content.
2177      * The message area will be transparent, uneditable, and word-wrapped. <br>
2178      * The resource used is:
2179      * <table>
2180      * <tr><td><i>uiKey</i>.txt  <td>the text for the message area
2181      * <tr><td><i>uiKey</i>.name  <td>accessible name
2182      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
2183      * </table>
2184      * @param uiKey the name of the resource to be used
2185      * @param args an array of arguments to be formatted into the content using
2186      * {@link java.text.MessageFormat#format}
2187      * @return the message area that was created
2188      */
2189     public JTextArea createMessageArea(String uiKey, Object[] args) {
2190         return createLocalizedMessageArea(uiKey, getI18NString(uiKey + ".txt", args), true);
2191     }
2192 
2193     /**
2194      * Only use this method if the origin of the message text is not coming from
2195      * a bundle.
2196      */
2197     private JTextArea createLiteralMessageArea(String msg) {
2198         JTextArea txt = new JTextArea(msg);
2199         txt.setName("literal");
2200         txt.setOpaque(false);
2201         txt.setEditable(false);
2202         txt.setLineWrap(true);
2203         txt.setWrapStyleWord(true);
2204         // The height is effectively ignored in the next line (just don't use 0.)
2205         // The text will be laid out, wrapping lines, for the width, and the
2206         // preferred height will thereby be determined accordingly.
2207         txt.setSize(new Dimension(7 * DOTS_PER_INCH, Integer.MAX_VALUE));
2208         // override JTextArea focus traversal keys, resetting them to
2209         // the Component default (i.e. the same as for the parent.)
2210         txt.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
2211         txt.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
2212         AccessibleContext ac = txt.getAccessibleContext();
2213         ac.setAccessibleName(local_i18n.getString("uif.message.name"));
2214         ac.setAccessibleDescription(local_i18n.getString("uif.message.desc"));
2215         return txt;
2216     }
2217 
2218 
2219     /**
2220      * @param std True if this area should be made accessible.
2221      */
2222     private JTextArea createLocalizedMessageArea(String uiKey, String msg, boolean std) {
2223         JTextArea txt = new JTextArea(msg);
2224         txt.setName(uiKey);
2225         txt.setOpaque(false);
2226         txt.setBackground(Colors.TRANSPARENT.getValue());
2227         txt.setEditable(false);
2228         txt.setLineWrap(true);
2229         txt.setWrapStyleWord(true);
2230         // The height is effectively ignored in the next line (just don't use 0.)
2231         // The text will be laid out, wrapping lines, for the width, and the
2232         // preferred height will thereby be determined accordingly.
2233         txt.setSize(new Dimension(7 * DOTS_PER_INCH, Integer.MAX_VALUE));
2234         // override JTextArea focus traversal keys, resetting them to
2235         // the Component default (i.e. the same as for the parent.)
2236         txt.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
2237         txt.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
2238         if (std) {
2239             AccessibleContext ac = txt.getAccessibleContext();
2240             ac.setAccessibleName(local_i18n.getString("uif.message.name"));
2241             ac.setAccessibleDescription(local_i18n.getString("uif.message.desc"));
2242         }
2243         else
2244             setAccessibleInfo(txt, uiKey);
2245         return txt;
2246     }
2247 
2248     /**
2249      * Create an output text field, using a resource to specify the tool tip.  <br>
2250      * The resource used is:
2251      * <table>
2252      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2253      * <tr><td><i>uiKey</i>.name <td>accessible name
2254      * </table>
2255      * In addition, the name of the output field is set to <i>uiKey</i>.
2256      * By default, the output field is empty and is 10 characters wide.
2257      * @param uiKey the base name of the resource to be used
2258      * @return the empty output field that was created
2259      * @see #createInputField
2260      */
2261     public JTextField createOutputField(String uiKey) {
2262         return createOutputField(uiKey, "", 10, null, false);
2263     }
2264 
2265     /**
2266      * Same as the single parameter version, except a label, which labels
2267      * this new component, will be set.
2268      * The label's <code>setLabelFor()</code> will be set.
2269      * @param uiKey the base name of the resource to be used
2270      * @param label the label which is labeling this field
2271      * @return the output field that was created
2272      * @see #createInputField(String)
2273      */
2274     public JTextField createOutputField(String uiKey, JLabel label) {
2275         return createOutputField(uiKey, "", 10, label, false);
2276     }
2277 
2278     /**
2279      * Create an output text field with a specified number of columns,
2280      * using a resource to specify the tool tip,
2281      * which can automaticly select contained text.<br>
2282      * The label's <code>setLabelFor()</code> will be set.
2283      * @param uiKey the base name of the resource to be used
2284      * @param label the label which is labeling this field
2285      * @param autoSelect automaticly select text containing in the field on focus
2286      * @return the output field that was created
2287      * @see #createInputField(String)
2288      */
2289     public JTextField createOutputField(String uiKey, JLabel label, boolean autoSelect) {
2290         return createOutputField(uiKey, "", 10, label, autoSelect);
2291     }
2292 
2293     /**
2294      * Create an output text field with a specified number of columns,
2295      * and using a resource to specify the tool tip.  <br>
2296      * The resource used is:
2297      * <table>
2298      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2299      * <tr><td><i>uiKey</i>.name <td>accessible name
2300      * </table>
2301      * In addition, the name of the output field is set to <i>uiKey</i>.
2302      * The output field is initially empty.
2303      * @param uiKey the base name of the resource to be used
2304      * @param cols the default width of the field, in characters
2305      * @return the empty output field that was created
2306      */
2307     public JTextField createOutputField(String uiKey, int cols) {
2308         return createOutputField(uiKey, "", cols, null, false);
2309     }
2310 
2311     /**
2312      * Create an output text field with a specified number of columns,
2313      * using a resource to specify the tool tip, with an attached label.  <br>
2314      * The resource used is:
2315      * <table>
2316      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2317      * <tr><td><i>uiKey</i>.name <td>accessible name
2318      * </table>
2319      * In addition, the name of the output field is set to <i>uiKey</i>.
2320      * The output field is initially empty.
2321      * @param uiKey the base name of the resource to be used
2322      * @param cols the default width of the field, in characters
2323      * @param label the label which is labeling this field
2324      * @return the empty output field that was created
2325      */
2326     public JTextField createOutputField(String uiKey, int cols, JLabel label) {
2327         return createOutputField(uiKey, "", cols, label, false);
2328     }
2329 
2330     /**
2331      * Create an output text field with a specified number of columns,
2332      * using a resource to specify the tool tip, with an attached label,
2333      * which can automaticly select contained text.<br>
2334      * The resource used is:
2335      * <table>
2336      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2337      * <tr><td><i>uiKey</i>.name <td>accessible name
2338      * </table>
2339      * In addition, the name of the output field is set to <i>uiKey</i>.
2340      * The output field is initially empty.
2341      * @param uiKey the base name of the resource to be used
2342      * @param cols the default width of the field, in characters
2343      * @param label the label which is labeling this field
2344      * @param autoSelect automaticly select text containing in the field on focus
2345      * @return the empty output field that was created
2346      */
2347     public JTextField createOutputField(String uiKey, int cols, JLabel label, boolean autoSelect) {
2348         return createOutputField(uiKey, "", cols, label, autoSelect);
2349     }
2350 
2351     /**
2352      * Create an output text field containing a specified value,
2353      * and using a resource to specify the tool tip.  <br>
2354      * The resource used is:
2355      * <table>
2356      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2357      * <tr><td><i>uiKey</i>.name <td>accessible name
2358      * </table>
2359      * In addition, the name of the output field is set to <i>uiKey</i>.
2360      * By default, the output field is 10 characters wide.
2361      * @param uiKey the base name of the resource to be used
2362      * @param value the initial text to appear in the output field
2363      * @return the output field that was created
2364      */
2365     public JTextField createOutputField(String uiKey, String value) {
2366         return createOutputField(uiKey, value, 10, null, false);
2367     }
2368 
2369     /**
2370      * Create an output text field containing a specified value,
2371      * using a resource to specify the tool tip,
2372      * with an attached label. <br>
2373      * The resource used is:
2374      * <table>
2375      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2376      * <tr><td><i>uiKey</i>.name <td>accessible name
2377      * </table>
2378      * In addition, the name of the output field is set to <i>uiKey</i>.
2379      * By default, the output field is 10 characters wide.
2380      * @param uiKey the base name of the resource to be used
2381      * @param value the text to appear in the output field
2382      * @param label the label which is labeling this field
2383      * @return the output field that was created
2384      */
2385     public JTextField createOutputField(String uiKey, String value, JLabel label) {
2386         return createOutputField(uiKey, value, 10, label, false);
2387     }
2388 
2389     /**
2390      * Create an output text field containing a specified value,
2391      * with a specified number of columns,
2392      * and using a resource to specify the tool tip.  <br>
2393      * The resource used is:
2394      * <table>
2395      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2396      * <tr><td><i>uiKey</i>.name <td>accessible name
2397      * </table>
2398      * In addition, the name of the output field is set to <i>uiKey</i>.
2399      * @param uiKey the base name of the resource to be used
2400      * @param value the text to appear in the output field
2401      * @param cols the default width of the field, in characters
2402      * @return the output field that was created
2403      */
2404     public JTextField createOutputField(String uiKey, String value, int cols) {
2405         return createOutputField(uiKey, value, cols, null, false);
2406     }
2407 
2408     /**
2409      * Create an output text field containing a specified value,
2410      * with a specified number of columns,
2411      * using a resource to specify the tool tip,
2412      * with a label referencing this new field.<br>
2413      * The resource used is:
2414      * <table>
2415      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2416      * <tr><td><i>uiKey</i>.name <td>accessible name
2417      * </table>
2418      * In addition, the name of the output field is set to <i>uiKey</i>.
2419      * @param uiKey the base name of the resource to be used
2420      * @param value the text to appear in the output field
2421      * @param cols the default width of the field, in characters
2422      * @param label the label which is labeling this field
2423      * @return the output field that was created
2424      */
2425     public JTextField createOutputField(String uiKey, String value, int cols, JLabel label) {
2426         return createOutputField(uiKey, value, cols, label, false);
2427     }
2428 
2429     /**
2430      * Create an output text field containing a specified value,
2431      * with a specified number of columns,
2432      * using a resource to specify the tool tip,
2433      * with a label referencing this new field,
2434      * which can automaticly select contained text.<br>
2435      * The resource used is:
2436      * <table>
2437      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the field
2438      * <tr><td><i>uiKey</i>.name <td>accessible name
2439      * </table>
2440      * In addition, the name of the output field is set to <i>uiKey</i>.
2441      * @param uiKey the base name of the resource to be used
2442      * @param value the text to appear in the output field
2443      * @param cols the default width of the field, in characters
2444      * @param label the label which is labeling this field
2445      * @param autoSelect automaticly select text containing in the field on focus
2446      * @return the output field that was created
2447      */
2448     public JTextField createOutputField(String uiKey, String value, int cols, JLabel label, boolean autoSelect) {
2449         final JTextField tf = new JTextField(value, cols);
2450         tf.setName(uiKey);
2451         tf.setEditable(false);
2452         tf.setBackground(Colors.TRANSPARENT.getValue());
2453         tf.setOpaque(false);
2454         if(autoSelect)
2455             tf.addFocusListener(new java.awt.event.FocusListener() {
2456                 public void focusGained(java.awt.event.FocusEvent e) {
2457                     tf.setSelectionStart(0);
2458                     tf.setSelectionEnd(tf.getText().length());
2459                 }
2460 
2461                 public void focusLost(java.awt.event.FocusEvent e) {
2462                     tf.setSelectionStart(0);
2463                     tf.setSelectionEnd(0);
2464                 }
2465             });
2466 
2467         if (label != null)
2468             label.setLabelFor(tf);
2469         else
2470             setAccessibleName(tf, uiKey);
2471 
2472         setToolTip(tf, uiKey);
2473         // override JTextField focus traversal keys, resetting them to
2474         // the Component default (i.e. the same as for the parent.)
2475         tf.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
2476         tf.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
2477         return tf;
2478     }
2479 
2480     /**
2481      * Create a text area, using a resource to specify the tool tip.  <br>
2482      * The resource used is:
2483      * <table>
2484      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the text area
2485      * </table>
2486      * In addition, the name of the text area is set to <i>uiKey</i>.
2487      * @param uiKey the base name of the resource to be used
2488      * @return the text area that was created
2489      */
2490     public JTextArea createTextArea(String uiKey) {
2491         return createTextArea(uiKey, null);
2492     }
2493 
2494     /**
2495      * Create a text area, using a resource to specify the tool tip.  <br>
2496      * The resource used is:
2497      * <table>
2498      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the text area
2499      * </table>
2500      * In addition, the name of the text area is set to <i>uiKey</i>.
2501      * @param uiKey the base name of the resource to be used
2502      * @param label the label that labels this text area.  May be null.
2503      * @return the text area that was created
2504      */
2505     public JTextArea createTextArea(String uiKey, JLabel label) {
2506         JTextArea t = new JTextArea() {
2507             public Dimension getPreferredScrollableViewportSize() {
2508                 return new Dimension(100, 100);
2509             }
2510         };
2511         t.setName(uiKey);
2512 
2513         if (label != null)
2514             label.setLabelFor(t);
2515         else
2516             setAccessibleName(t, uiKey);
2517 
2518         setToolTip(t, uiKey);
2519         return t;
2520     }
2521 
2522     //----------------------------------------------------------------------------
2523     //
2524     // progress bars
2525 
2526     /**
2527      * Create a basic progress bar.
2528      * The resource used is:
2529      * <table>
2530      * <tr><td><i>uiKey</i>.name <td>accessible name
2531      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the text area
2532      * </table>
2533      *
2534      * @param uiKey the base name of the resource to be used
2535      * @param orient Value from <code>JProgressBar</code>
2536      * @return Returns a progress bar component with the specified attributes.
2537      * @see javax.swing.JProgressBar#VERTICAL
2538      * @see javax.swing.JProgressBar#HORIZONTAL
2539      */
2540     public JProgressBar createProgressBar(String uiKey, int orient) {
2541         JProgressBar pb = new JProgressBar(orient);
2542         setToolTip(pb, uiKey);
2543         setAccessibleName(pb, uiKey);
2544 
2545         return pb;
2546     }
2547 
2548     /**
2549      * Create a basic progress bar.
2550      * The resources used are:
2551      * <table>
2552      * <tr><td><i>uiKey</i>.name <td>accessible name
2553      * <tr><td><i>uiKey</i>.tip  <td>the tool tip for the text area
2554      * </table>
2555      *
2556      * @param uiKey the base name of the resource to be used
2557      * @param orient Value from <code>JProgressBar</code>
2558      * @param model Model to use for the progress bar.
2559      * @return Returns a progress bar component with the specified attributes.
2560      * @see javax.swing.JProgressBar#VERTICAL
2561      * @see javax.swing.JProgressBar#HORIZONTAL
2562      */
2563     public JProgressBar createProgressBar(String uiKey, int orient,
2564                             BoundedRangeModel model) {
2565         JProgressBar pb = createProgressBar(uiKey, orient);
2566         pb.setModel(model);
2567 
2568         return pb;
2569     }
2570 
2571     //----------------------------------------------------------------------------
2572     //
2573     // toolbar
2574 
2575     /**
2576      * Create an empty toolbar.
2577      * The resources used are:
2578      * <table>
2579      * <tr><td><i>uiKey</i>.name  <td>accessible name
2580      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
2581      * </table>
2582      * @param uiKey Used to obtain accessibility info and name the component
2583      * @return the tool bar that was created
2584      */
2585     public JToolBar createToolBar(String uiKey) {
2586         JToolBar tb = new JToolBar();
2587         tb.setName(uiKey);
2588         setAccessibleInfo(tb, uiKey);
2589 
2590         return tb;
2591     }
2592 
2593     /**
2594      * Create a toolbar, using actions to specify the buttons,
2595      * and using resources to specify the name and mnemonic. <br>
2596      * The components on the toolbar which are derived from the actions will
2597      * have their accessible description set to the short description of the
2598      * action.
2599      * The resources used are:
2600      * <table>
2601      * <tr><td><i>uiKey</i>.name  <td>accessible name
2602      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
2603      * </table>
2604      * @param uiKey used to obtain accessibility info and name the component
2605      * @param actions the actions from which to create the buttons;
2606      *  use null in the array to indicate if and where a separator is required
2607      * @return the tool bar that was created
2608      * @see javax.swing.Action#SHORT_DESCRIPTION
2609      */
2610     public JToolBar createToolBar(String uiKey, Action[] actions) {
2611         JToolBar tb = new JToolBar();
2612         tb.setName(uiKey);
2613         setAccessibleInfo(tb, uiKey);
2614         for (int i = 0; i < actions.length; i++) {
2615             Action action = actions[i];
2616             if (action == null)
2617                 tb.addSeparator();
2618             else {
2619                 JButton b = tb.add(action);
2620                 b.setName((String) (action.getValue(Action.NAME)));
2621                 b.getAccessibleContext().setAccessibleName(b.getName());
2622             }
2623         }
2624         return tb;
2625     }
2626 
2627     /**
2628      * Create a toolbar, using buttons.
2629      * The resources used are:
2630      * <table>
2631      * <tr><td><i>uiKey</i>.name  <td>accessible name
2632      * <tr><td><i>uiKey</i>.desc  <td>accessible description text
2633      * </table>
2634      * @param uiKey used to obtain accessibility info and name the component
2635      * @param buttons the buttons to be included in the bar.<br>
2636      *  use null in the array to indicate if and where a separator is required
2637      * @return the tool bar that was created
2638      */
2639     public JToolBar createToolBar(String uiKey, JButton[] buttons) {
2640         JToolBar tb = new JToolBar();
2641         tb.setName(uiKey);
2642         setAccessibleInfo(tb, uiKey);
2643         for (int i = 0; i < buttons.length; i++) {
2644             JButton button = buttons[i];
2645             if (button == null)
2646                 tb.addSeparator();
2647             else {
2648                 tb.add(button);
2649             }
2650         }
2651         return tb;
2652     }
2653 
2654     /**
2655      * Add a set of actions to an existing toolbar.
2656      *
2657      * @param tb The toolbar to modify, must not be null.
2658      * @param actions the actions from which to create the buttons;
2659      *        use null in the array to indicate if and where a separator is required
2660      * @see javax.swing.Action#SHORT_DESCRIPTION
2661      */
2662     public void addToolBarActions(JToolBar tb, Action[] actions) {
2663         for (int i = 0; i < actions.length; i++) {
2664             Action action = actions[i];
2665             if (action == null)
2666                 tb.addSeparator();
2667             else {
2668                 JButton b = tb.add(action);
2669                 b.setName((String) (action.getValue(Action.NAME)));
2670                 b.getAccessibleContext().setAccessibleName(b.getName());
2671             }
2672         }
2673     }
2674 
2675     //----------------------------------------------------------------------------
2676     //
2677     // blocking confirmation and error dialogs
2678 
2679     /**
2680      * Show an information dialog, using a resource to specify the error message. <br>
2681      * The resource used is:
2682      * <table>
2683      * <tr><td><i>uiKey</i>.err  <td>the information message to be displayed
2684      * </table>
2685      * The method will block until the dialog is dismissed by the user.
2686      * @param uiKey the base name of the resource to be used
2687      */
2688     public void showInformation(String uiKey) {
2689         showLocalizedInfo(uiKey, getI18NString(uiKey + ".inf"));
2690     }
2691 
2692     /**
2693      * Show an error dialog, using a resource to specify the error message. <br>
2694      * The resource used is:
2695      * <table>
2696      * <tr><td><i>uiKey</i>.err  <td>the error message to be displayed
2697      * </table>
2698      * The method will block until the dialog is dismissed by the user.
2699      * @param uiKey the base name of the resource to be used
2700      */
2701     public void showError(String uiKey) {
2702         showLocalizedError(uiKey, getI18NString(uiKey + ".err"));
2703     }
2704 
2705     /**
2706      * Show an error dialog, using a resource to specify the error message. <br>
2707      * The resource used is:
2708      * <table>
2709      * <tr><td><i>uiKey</i>.err  <td>the error message to be displayed
2710      * </table>
2711      * @param uiKey the base name of the resource to be used
2712      * @param arg an argument to be formatted into the content using
2713      * {@link java.text.MessageFormat#format}
2714      * The method will block until the dialog is dismissed by the user.
2715      */
2716     public void showError(String uiKey, Object arg) {
2717         showLocalizedError(uiKey, getI18NString(uiKey + ".err", arg));
2718     }
2719 
2720     /**
2721      * Show an error dialog, using a resource to specify the error message. <br>
2722      * The resource used is:
2723      * <table>
2724      * <tr><td><i>uiKey</i>.err  <td>the error message to be displayed
2725      * </table>
2726      * @param uiKey the base name of the resource to be used
2727      * @param args an array of arguments to be formatted into the content using
2728      * {@link java.text.MessageFormat#format}
2729      * The method will block until the dialog is dismissed by the user.
2730      */
2731     public void showError(String uiKey, Object[] args) {
2732         String msg = getI18NString(uiKey + ".err", args);
2733         String title = local_i18n.getString("uif.error", ProductInfo.getName());
2734         JButton okBtn = createOptionButton("uif.ok");
2735         JTextArea ta = createLocalizedMessageArea(uiKey, msg.trim(), true);
2736         Dimension d = ta.getMinimumSize();
2737         Object content = ta;
2738         // need scrolling ?
2739         if (d.width > Math.round(6.f * DOTS_PER_INCH) || d.height > Math.round(2.f * DOTS_PER_INCH)) {
2740             JScrollPane sp = new JScrollPane(ta);
2741             sp.setPreferredSize(new Dimension(Math.round(6.f * DOTS_PER_INCH),
2742                                     Math.round(2.f * DOTS_PER_INCH)));
2743             content = sp;
2744         }
2745 
2746         JOptionPane.showOptionDialog(parent,
2747                                      content,
2748                                      title,
2749                                      JOptionPane.DEFAULT_OPTION,
2750                                      JOptionPane.ERROR_MESSAGE,
2751                                      null,
2752                                      new Object[] { okBtn },
2753                                      null);
2754     }
2755 
2756     /**
2757      * Show an error dialog containing stack trace information, using a
2758      * resource to specify the error message. <br>
2759      * The resource used is:
2760      * <table>
2761      * <tr><td><i>uiKey</i>.err  <td>the error message to be displayed
2762      * </table>
2763      * @param uiKey the base name of the resource to be used
2764      * @param args an array of arguments to be formatted into the content using
2765      * @param trace an array of arguments containing stack trace information
2766      * to be added to scrollable pane
2767      * The method will block until the dialog is dismissed by the user.
2768      */
2769     public void showError(String uiKey, Object[] args, Object[] trace) {
2770         String title = local_i18n.getString("uif.error", ProductInfo.getName());
2771         JButton okBtn = createOptionButton("uif.ok");
2772         StringBuffer traceString = new StringBuffer(getI18NString(uiKey + ".err", args));
2773         traceString.append(":\n");
2774         for (int i = 0; i < trace.length; i++) {
2775             traceString.append(trace[i]);
2776             if (i != (trace.length -1))
2777                 traceString.append("\n\tat ");
2778         }
2779         JTextArea ta = createLocalizedMessageArea(uiKey, traceString.toString(), true);
2780         ta.setLineWrap(false);
2781         JScrollPane sp = new JScrollPane(ta);
2782         sp.setPreferredSize(new Dimension(Math.round(6.f * DOTS_PER_INCH),
2783                                 Math.round(2.f * DOTS_PER_INCH)));
2784 
2785         JOptionPane.showOptionDialog(parent,
2786                                      sp,
2787                                      title,
2788                                      JOptionPane.DEFAULT_OPTION,
2789                                      JOptionPane.ERROR_MESSAGE,
2790                                      null,
2791                                      new Object[] { okBtn },
2792                                      null);
2793     }
2794 
2795     /**
2796      * Show a error dialog to the user, using previously localized (or
2797      * unlocalized) strings for the message and title.
2798      * @param title Title string for the dialog.  If null, a generic title
2799      *              will be used.
2800      * @param msg Message to show to the user.
2801      * @see #showError(String)
2802      * @see #showError(String,Object[])
2803      * @see #showError(String,Object[],Object[])
2804      */
2805     public void showLiteralError(String title, String msg) {
2806         JButton okBtn = createOptionButton("uif.ok");
2807         if (title == null)
2808             title = local_i18n.getString("uif.error", ProductInfo.getName());
2809 
2810         JOptionPane.showOptionDialog(parent,
2811                                      createLiteralMessageArea(msg),
2812                                      title,
2813                                      JOptionPane.DEFAULT_OPTION,
2814                                      JOptionPane.ERROR_MESSAGE,
2815                                      null,
2816                                      new Object[] { okBtn },
2817                                      null);
2818     }
2819 
2820     private void showLocalizedError(String uiKey, String text) {
2821         String title = local_i18n.getString("uif.error", ProductInfo.getName());
2822         JButton okBtn = createOptionButton("uif.ok");
2823         JOptionPane.showOptionDialog(parent,
2824                                      createLocalizedMessageArea(uiKey, text, true),
2825                                      title,
2826                                      JOptionPane.DEFAULT_OPTION,
2827                                      JOptionPane.ERROR_MESSAGE,
2828                                      null,
2829                                      new Object[] { okBtn },
2830                                      null);
2831     }
2832 
2833 
2834     private void showLocalizedInfo(String uiKey, String text) {
2835         String title = i18n.getString(uiKey + ".title");
2836         JButton okBtn = createOptionButton("uif.ok");
2837         JOptionPane.showOptionDialog(parent,
2838                                      createLocalizedMessageArea(uiKey, text, true),
2839                                      title,
2840                                      JOptionPane.DEFAULT_OPTION,
2841                                      JOptionPane.INFORMATION_MESSAGE,
2842                                      null,
2843                                      new Object[] { okBtn },
2844                                      null);
2845     }
2846 
2847     /**
2848      * Show a confirmation dialog with OK and Cancel buttons,
2849      * using a resource to specify the message and title. <br>
2850      * The resources used are:
2851      * <table>
2852      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2853      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2854      * </table>
2855      * The method will block until the dialog is dismissed by the user.
2856      * @param uiKey the base name of the resource to be used
2857      * @return an integer signifying how the dialog was dismissed
2858      * @see JOptionPane#OK_OPTION
2859      * @see JOptionPane#CANCEL_OPTION
2860      */
2861     public int showOKCancelDialog(String uiKey) {
2862         return showLocalizedOKCancelDialog(uiKey, getI18NString(uiKey + ".txt"));
2863     }
2864 
2865     /**
2866      * Show a confirmation dialog with OK and Cancel buttons,
2867      * using a resource to specify the message and title. <br>
2868      * The resources used are:
2869      * <table>
2870      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2871      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2872      * </table>
2873      * The method will block until the dialog is dismissed by the user.
2874      * @param uiKey the base name of the resource to be used
2875      * @param arg an argument to be formatted into the content using
2876      * {@link java.text.MessageFormat#format}
2877      * @return an integer signifying how the dialog was dismissed
2878      * @see JOptionPane#OK_OPTION
2879      * @see JOptionPane#CANCEL_OPTION
2880      */
2881     public int showOKCancelDialog(String uiKey, Object arg) {
2882         return showLocalizedOKCancelDialog(uiKey, getI18NString(uiKey + ".txt", arg));
2883     }
2884 
2885     /**
2886      * Show a confirmation dialog with OK and Cancel buttons,
2887      * using a resource to specify the message and title. <br>
2888      * The resources used are:
2889      * <table>
2890      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2891      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2892      * </table>
2893      * The method will block until the dialog is dismissed by the user.
2894      * @param uiKey the base name of the resource to be used
2895      * @return an integer signifying how the dialog was dismissed
2896      * @param args an array of arguments to be formatted into the content using
2897      * {@link java.text.MessageFormat#format}
2898      * @see JOptionPane#OK_OPTION
2899      * @see JOptionPane#CANCEL_OPTION
2900      */
2901     public int showOKCancelDialog(String uiKey, Object[] args) {
2902         return showLocalizedOKCancelDialog(uiKey, getI18NString(uiKey + ".txt", args));
2903     }
2904 
2905     private int showLocalizedOKCancelDialog(String uiKey, String text) {
2906         JTextArea msg = createLocalizedMessageArea(uiKey, text, true);
2907         String title = getI18NString(uiKey + ".title");
2908         JButton okBtn = createOptionButton("uif.ok");
2909         JButton cancelBtn = createOptionButton("uif.cancel");
2910         int rc = JOptionPane.showOptionDialog(parent,
2911                                               msg,
2912                                               title,
2913                                               JOptionPane.OK_CANCEL_OPTION,
2914                                               JOptionPane.QUESTION_MESSAGE,
2915                                               null,
2916                                               new Object[] { okBtn, cancelBtn },
2917                                               null);
2918         return (rc == 0 ? JOptionPane.OK_OPTION /*0*/
2919                 : rc == 1 ? JOptionPane.CANCEL_OPTION /*2*/
2920                 : rc);
2921     }
2922 
2923     /**
2924      * Show a confirmation dialog with Yes and No buttons,
2925      * using a resource to specify the message and title. <br>
2926      * The resources used are:
2927      * <table>
2928      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2929      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2930      * </table>
2931      * The method will block until the dialog is dismissed by the user.
2932      * @param uiKey the base name of the resource to be used
2933      * @return an integer signifying how the dialog was dismissed
2934      * @see JOptionPane#YES_OPTION
2935      * @see JOptionPane#NO_OPTION
2936      */
2937     public int showYesNoDialog(String uiKey) {
2938         return showLocalizedYesNoDialog(uiKey, getI18NString(uiKey + ".txt"));
2939     }
2940 
2941     /**
2942      * Show a confirmation dialog with Yes and No buttons,
2943      * using a resource to specify the message and title. <br>
2944      * The resources used are:
2945      * <table>
2946      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2947      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2948      * </table>
2949      * The method will block until the dialog is dismissed by the user.
2950      * @param uiKey the base name of the resource to be used
2951      * @param arg an argument to be formatted into the content using
2952      * {@link java.text.MessageFormat#format}
2953      * @return an integer signifying how the dialog was dismissed
2954      * @see JOptionPane#YES_OPTION
2955      * @see JOptionPane#NO_OPTION
2956      */
2957     public int showYesNoDialog(String uiKey, Object arg) {
2958         return showLocalizedYesNoDialog(uiKey, getI18NString(uiKey + ".txt", arg));
2959     }
2960 
2961     /**
2962      * Show a confirmation dialog with Yes and No buttons,
2963      * using a resource to specify the title and component for the message.<br>
2964      * The resources used are:
2965      * <table>
2966      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2967      * </table>
2968      * The method will block until the dialog is dismissed by the user.
2969      * @param uiKey the base name of the resource to be used
2970      * @param msg the GUI component to be used as the dialogs message payload
2971      * @return an integer signifying how the dialog was dismissed
2972      * @see JOptionPane#YES_OPTION
2973      * @see JOptionPane#NO_OPTION
2974      */
2975     public int showCustomYesNoDialog(String uiKey, Component msg) {
2976         return showComponentYesNoDialog(uiKey, msg);
2977     }
2978 
2979     /**
2980      * Show a confirmation dialog with Yes and No buttons,
2981      * using a resource to specify the message and title. <br>
2982      * The resources used are:
2983      * <table>
2984      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
2985      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
2986      * </table>
2987      * The method will block until the dialog is dismissed by the user.
2988      * @param uiKey the base name of the resource to be used
2989      * @return an integer signifying how the dialog was dismissed
2990      * @param args an array of arguments to be formatted into the content using
2991      * {@link java.text.MessageFormat#format}
2992      * @see JOptionPane#YES_OPTION
2993      * @see JOptionPane#NO_OPTION
2994      */
2995     public int showYesNoDialog(String uiKey, Object[] args) {
2996         return showLocalizedYesNoDialog(uiKey, getI18NString(uiKey + ".txt", args));
2997     }
2998 
2999     private int showLocalizedYesNoDialog(String uiKey, String text) {
3000         JTextArea msg = createLocalizedMessageArea(uiKey, text, true);
3001         return showComponentYesNoDialog(uiKey, msg);
3002     }
3003 
3004     /**
3005      * Show a Yes/No dialog with the given text and title.
3006      * Use this with care and only when really really needed.
3007      */
3008     int showLiteralYesNoDialog(String title, String text) {
3009         // warning, this only works because createLocalizedMessageArea
3010         // does not use the uikey for anything except the component name
3011         JTextArea msg = createLocalizedMessageArea("literal", text, true);
3012 
3013         // update showComponentYesNoDialog if you change this!
3014         JButton yesBtn = createOptionButton("uif.yes");
3015         JButton noBtn = createOptionButton("uif.no");
3016         return JOptionPane.showOptionDialog(parent,
3017                                             msg,
3018                                             title,
3019                                             JOptionPane.YES_NO_OPTION,
3020                                             JOptionPane.QUESTION_MESSAGE,
3021                                             null,
3022                                             new Object[] { yesBtn, noBtn },
3023                                             null);
3024     }
3025 
3026     private int showComponentYesNoDialog(String uiKey, Component msg) {
3027         // update showLiteralYesNoDialog if you change this!
3028         String title = getI18NString(uiKey + ".title");
3029         JButton yesBtn = createOptionButton("uif.yes");
3030         JButton noBtn = createOptionButton("uif.no");
3031         return JOptionPane.showOptionDialog(parent,
3032                                             msg,
3033                                             title,
3034                                             JOptionPane.YES_NO_OPTION,
3035                                             JOptionPane.QUESTION_MESSAGE,
3036                                             null,
3037                                             new Object[] { yesBtn, noBtn },
3038                                             null);
3039     }
3040 
3041     /**
3042      * Show a confirmation dialog with Yes, No and Cancel buttons,
3043      * using a resource to specify the message and title. <br>
3044      * The resources used are:
3045      * <table>
3046      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3047      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3048      * </table>
3049      * The method will block until the dialog is dismissed by the user.
3050      * @param uiKey the base name of the resource to be used
3051      * @return an integer signifying how the dialog was dismissed
3052      * @see JOptionPane#YES_OPTION
3053      * @see JOptionPane#NO_OPTION
3054      * @see JOptionPane#CANCEL_OPTION
3055      */
3056     public int showYesNoCancelDialog(String uiKey) {
3057         return showLocalizedYesNoCancelDialog(uiKey, getI18NString(uiKey + ".txt"));
3058     }
3059 
3060     /**
3061      * Show a confirmation dialog with Yes and No buttons,
3062      * using a resource to specify the message and title. <br>
3063      * The resources used are:
3064      * <table>
3065      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3066      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3067      * </table>
3068      * The method will block until the dialog is dismissed by the user.
3069      * @param uiKey the base name of the resource to be used
3070      * @param arg an argument to be formatted into the content using
3071      * {@link java.text.MessageFormat#format}
3072      * @return an integer signifying how the dialog was dismissed
3073      * @see JOptionPane#YES_OPTION
3074      * @see JOptionPane#NO_OPTION
3075      * @see JOptionPane#CANCEL_OPTION
3076      */
3077     public int showYesNoCancelDialog(String uiKey, Object arg) {
3078         return showLocalizedYesNoCancelDialog(uiKey, getI18NString(uiKey + ".txt", arg));
3079     }
3080 
3081     /**
3082      * Show a confirmation dialog with Yes and No buttons,
3083      * using a resource to specify the message and title. <br>
3084      * The resources used are:
3085      * <table>
3086      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3087      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3088      * </table>
3089      * The method will block until the dialog is dismissed by the user.
3090      * @param uiKey the base name of the resource to be used
3091      * @return an integer signifying how the dialog was dismissed
3092      * @param args an array of arguments to be formatted into the content using
3093      * {@link java.text.MessageFormat#format}
3094      * @see JOptionPane#YES_OPTION
3095      * @see JOptionPane#NO_OPTION
3096      * @see JOptionPane#CANCEL_OPTION
3097      */
3098     public int showYesNoCancelDialog(String uiKey, Object[] args) {
3099         return showLocalizedYesNoCancelDialog(uiKey, getI18NString(uiKey + ".txt", args));
3100     }
3101 
3102     private int showLocalizedYesNoCancelDialog(String uiKey, String text) {
3103         JTextArea msg = createLocalizedMessageArea(uiKey, text, true);
3104         String title = getI18NString(uiKey + ".title");
3105         JButton yesBtn = createOptionButton("uif.yes");
3106         JButton noBtn = createOptionButton("uif.no");
3107         JButton cancelBtn = createOptionButton("uif.cancel");
3108         return JOptionPane.showOptionDialog(parent,
3109                                             msg,
3110                                             title,
3111                                             JOptionPane.YES_NO_CANCEL_OPTION,
3112                                             JOptionPane.QUESTION_MESSAGE,
3113                                             null,
3114                                             new Object[] { yesBtn, noBtn, cancelBtn },
3115                                             null);
3116     }
3117 
3118     /**
3119      * Show a message only dialog, no user feedback.
3120      * The resources used are:
3121      * <table>
3122      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3123      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3124      * </table>
3125      * @param uiKey the base name of the resource to be used
3126      * @param args any arguments to be used to create the message
3127      */
3128     public void showInformationDialog(String uiKey, Object[] args) {
3129         showLocalizedInformationDialog(uiKey,
3130             getI18NString(uiKey + ".title"),
3131             getI18NString(uiKey + ".txt", args), parent);
3132     }
3133 
3134     public void showInformationDialog(String uiKey, Object[] args, Component parent) {
3135         showLocalizedInformationDialog(uiKey,
3136             getI18NString(uiKey + ".title"),
3137             getI18NString(uiKey + ".txt", args), parent);
3138     }
3139 
3140 
3141     private void showLocalizedInformationDialog(String uiKey, String title,
3142                                                 String text, Component localParent) {
3143         JTextArea msg = createLocalizedMessageArea(uiKey, text, true);
3144         Dimension d = msg.getMinimumSize();
3145         Object content = msg;
3146         // need scrolling ?
3147         if (d.width > Math.round(6.f * DOTS_PER_INCH) || d.height > Math.round(2.f * DOTS_PER_INCH)) {
3148             JScrollPane sp = new JScrollPane(msg);
3149             sp.setPreferredSize(new Dimension(Math.round(6.f * DOTS_PER_INCH),
3150                                     Math.round(2.f * DOTS_PER_INCH)));
3151             content = sp;
3152         }
3153 
3154         JOptionPane.showMessageDialog(localParent,
3155                                         content,
3156                                         title,
3157                                         JOptionPane.INFORMATION_MESSAGE,
3158                                         null);
3159     }
3160 
3161     //----------------------------------------------------------------------------
3162     //
3163     // don't show this again message box
3164 
3165     /**
3166      * Show a dialog which provides the user with an informational message.
3167      *
3168      * The resources used are:
3169      * <table>
3170      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3171      * </table>
3172      * @param uiKey the base name of the resource to be used
3173      * @param msg the body of the dialog, which should have already been localized
3174      */
3175     public void showCustomInfoDialog(String uiKey, Object msg) {
3176         JOptionPane.showMessageDialog(parent,
3177                                         msg,
3178                                         getI18NString(uiKey + ".title"),
3179                                         JOptionPane.INFORMATION_MESSAGE,
3180                                         null);
3181     }
3182 
3183     //----------------------------------------------------------------------------
3184     //
3185     // panels
3186 
3187     /**
3188      * Create a horizontal placeholder "box". <br>
3189      * The name of this new box component will be set to <i>uiKey</i>.
3190      * @param uiKey the base name of the resource to be used
3191      * @return A Box component
3192      * @see javax.swing.Box
3193      */
3194     public Box createHorizontalBox(String uiKey) {
3195         Box box = Box.createHorizontalBox();
3196         box.setName(uiKey);
3197         box.setFocusable(false);
3198         return box;
3199     }
3200 
3201     /**
3202      * Create an empty panel.  <br>
3203      * In the J2SE 1.4 and greater world, panels are focusable by default,
3204      * so this panel will be focusable.  Because of this, accessibility
3205      * information must be set, therefore the following resources are
3206      * required from the resource bundle:
3207      * <table>
3208      * <tr><td><i>uiKey</i>.name  <td>the accessible name of the panel
3209      * <tr><td><i>uiKey</i>.desc <td>accessible description text
3210      * </table>
3211      * The name of this new component will be set to <i>uiKey</i>.
3212      * @param uiKey the base name of the resource to be used
3213      * @return An empty panel component
3214      */
3215     public JPanel createPanel(String uiKey) {
3216         return createPanel(uiKey, true);
3217     }
3218 
3219     /**
3220      * Create an empty panel.  <br>
3221      * In the J2SE 1.4 and greater world, panels are focusable by default,
3222      * so this panel will be focusable.  Use this method to control
3223      * whether or not the panel remains focusable.  If you choose 'true',
3224      * the following must be provided in the resource bundle:
3225      * <table>
3226      * <tr><td><i>uiKey</i>.name  <td>the accessible name of the panel
3227      * <tr><td><i>uiKey</i>.desc <td>accessible description text
3228      * </table>
3229      * The name of this new component will be set to <i>uiKey</i>.
3230      * @param uiKey the base name of the resource to be used
3231      * @param focusable If true, the panel will accept focus in the GUI.
3232      *        If false it will not.  Note that if it is focusable, you need to
3233      *        provide accessibility text.
3234      * @return An empty panel component
3235      */
3236     public JPanel createPanel(String uiKey, boolean focusable) {
3237         JPanel p = new JPanel();
3238         initPanel(p, uiKey, focusable);
3239         return p;
3240     }
3241 
3242     /**
3243      * Create an empty panel with a specific layout manager.  <br>
3244      * In the J2SE 1.4 and greater world, panels are focusable by default,
3245      * so this panel will be focusable.  Because of this, accessibility
3246      * information must be set, therefore the following resources are
3247      * required from the resource bundle:
3248      * <table>
3249      * <tr><td><i>uiKey</i>.name  <td>the accessible name of the panel
3250      * <tr><td><i>uiKey</i>.desc <td>accessible description text
3251      * </table>
3252      * The name of this new component will be set to <i>uiKey</i>.
3253      * @param uiKey the base name of the resource to be used
3254      * @param layout the layout manager instance to use in this panel
3255      * @return An empty panel component
3256      */
3257     public JPanel createPanel(String uiKey, LayoutManager layout) {
3258         return createPanel(uiKey, layout, true);
3259     }
3260 
3261     /**
3262      * Create an empty panel with a specific layout manager.  <br>
3263      * In the J2SE 1.4 and greater world, panels are focusable by default,
3264      * so this panel will be focusable.  Use this method to control
3265      * whether or not the panel remains focusable.  If you choose 'true',
3266      * the following must be provided in the resource bundle:
3267      * <table>
3268      * <tr><td><i>uiKey</i>.name <td>the accessible name of the panel
3269      * <tr><td><i>uiKey</i>.desc <td>accessible description text
3270      * </table>
3271      * The name of this new component will be set to <i>uiKey</i>.
3272      * @param uiKey the base name of the resource to be used
3273      * @param layout the layout manager instance to use in this panel
3274      * @param focusable If true, the panel will accept focus in the GUI.
3275      *        If false it will not.  Note that if it is focusable, you need to
3276      *        provide accessibility text.
3277      * @return An empty panel component
3278      */
3279     public JPanel createPanel(String uiKey, LayoutManager layout, boolean focusable) {
3280         JPanel p = new JPanel();
3281         initPanel(p, uiKey, layout, focusable);
3282         return p;
3283     }
3284 
3285     /**
3286      * Set properties on an existing panel.
3287      * @param p the panel to modify
3288      * @param uiKey the base name of the resource to be used
3289      * @param focusable If true, the panel will accept focus in the GUI.
3290      *        If false it will not.  Note that if it is focusable, you need to
3291      *        provide accessibility text.
3292      */
3293     public void initPanel(JPanel p, String uiKey, boolean focusable) {
3294         p.setName(uiKey);
3295         if (focusable)
3296             setAccessibleInfo(p, uiKey);
3297         else
3298             p.setFocusable(false);
3299     }
3300 
3301     /**
3302      * Set properties on an existing panel, including the layout manager.
3303      * @param p the panel to modify
3304      * @param uiKey the base name of the resource to be used
3305      * @param layout the layout manager instance that this panel should use
3306      * @param focusable If true, the panel will accept focus in the GUI.
3307      *        If false it will not.  Note that if it is focusable, you need to
3308      *        provide accessibility text.
3309      */
3310     public void initPanel(JPanel p, String uiKey, LayoutManager layout, boolean focusable) {
3311         initPanel(p, uiKey, focusable);
3312         p.setLayout(layout);
3313 
3314     }
3315 
3316     //----------------------------------------------------------------------------
3317     //
3318     // dialogs
3319 
3320     /**
3321      * Create an empty dialog. <br>
3322      * See <code>initDialog(JDialog,String)</code> for required resources.
3323      * @param uiKey the base name of the resource to be used
3324      * @param parent the parent component of this dialog
3325      * @return an empty dialog component
3326      * @see #initDialog
3327      */
3328     public JDialog createDialog(String uiKey, Component parent) {
3329         JFrame owner = (JFrame) (SwingUtilities.getAncestorOfClass(JFrame.class, parent));
3330         return createDialog(uiKey, owner);
3331     }
3332 
3333     /**
3334      * Create an empty dialog. <br>
3335      * See <code>initDialog(JDialog,String)</code> for required resources.
3336      * @param uiKey the base name of the resource to be used
3337      * @param owner the parent frame of this dialog
3338      * @return an empty dialog component
3339      * @see #initDialog
3340      */
3341     public JDialog createDialog(String uiKey, JFrame owner) {
3342         JDialog d = new JDialog(owner);
3343         initDialog(d, uiKey);
3344         return d;
3345     }
3346 
3347     /**
3348      * Create an empty dialog. <br>
3349      * See <code>initDialog(JDialog,String)</code> for required resources.
3350      * @param uiKey the base name of the resource to be used
3351      * @param owner the parent frame of this dialog. If owner is null - icon is set to the dialog
3352      * @param title the localized title of this new dialog
3353      * @param content the content to go into the dialog
3354      * @return an dialog component with the given content component and title
3355      * @see #initDialog
3356      */
3357     public JDialog createDialog(String uiKey, JFrame owner, String title, Container content) {
3358         return createDialog(uiKey, owner, title, content, Dialog.ModalityType.MODELESS);
3359     }
3360 
3361     /**
3362      * Create an empty dialog. <br>
3363      * See <code>initDialog(JDialog,String)</code> for required resources.
3364      * @param uiKey the base name of the resource to be used
3365      * @param owner the parent frame of this dialog. If owner is null - icon is set to the dialog
3366      * @param title the localized title of this new dialog
3367      * @param content the content to go into the dialog
3368      * @param type specifies whether dialog blocks input to other windows when shown.
3369      * null value and unsupported modality types are equivalent to MODELESS
3370      * @return an dialog component with the given content component and title
3371      * @see #initDialog
3372      */
3373     public JDialog createDialog(String uiKey, JFrame owner, String title, Container content, Dialog.ModalityType type) {
3374         // can't use constructor JDialog(Window, String, Dialog.ModalityType) -
3375         // it has different behavior from JDialog(Frame, String, boolean)
3376         JDialog d = new JDialog(owner, title, false);
3377         d.setModalityType(type);
3378         if (owner == null) {
3379             d.setIconImage(createImage("images/jticon.gif"));
3380         }
3381         initDialog(d, uiKey);
3382         d.setContentPane(content);
3383         return d;
3384     }
3385 
3386     /**
3387      * Create an empty frame. Unlike to dialog <code>createDialog(String uiKey,
3388      * JFrame owner, String title, Container content)</code> it can't be modal,
3389      * it's always free-floating and it has minimize and maximize buttons <br/>
3390      * See <code>initFrame(JFrame,String)</code> for required resources.
3391      * @param uiKey the base name of the resource to be used
3392      * @param title the localized title of this new frame
3393      * @param content the content to go into the frame
3394      * @return a frame component with the given content component and title
3395      * @see #initFrame
3396      */
3397     public JFrame createFrame(String uiKey, String title, Container content) {
3398         JFrame frame = new JFrame(title);
3399         initFrame(frame, uiKey);
3400         frame.setContentPane(content);
3401         return frame;
3402     }
3403 
3404     /**
3405      * Create a dialog which will ask the user to wait.
3406      * The resources used are:
3407      * <table>
3408      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3409      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3410      * </table>
3411      * @param uiKey The prefix to retrieve strings to be displayed.
3412      * @param parent The parent component of this new dialog.
3413      * @return a dialog appropriate for asking the user to wait
3414      */
3415     public JDialog createWaitDialog(String uiKey, Component parent) {
3416         JFrame owner = (JFrame) (SwingUtilities.getAncestorOfClass(JFrame.class, parent));
3417         return createWaitDialog(uiKey, owner);
3418     }
3419 
3420     /**
3421      * Create a dialog which will ask the user to wait.
3422      * The resources used are:
3423      * <table>
3424      * <tr><td><i>uiKey</i>.txt  <td>the message to be displayed
3425      * <tr><td><i>uiKey</i>.title  <td>the title for the dialog
3426      * <tr><td><i>uiKey</i>.desc <td>accessible description of the dialog
3427      * <tr><td><i>uiKey</i>.name <td>accessible name of the dialog
3428      * </table>
3429      * @param uiKey The prefix to retrieve strings to be displayed.
3430      * @param owner The frame which will own this new dialog.
3431      * @return a dialog appropriate for asking the user to wait
3432      */
3433     public JDialog createWaitDialog(String uiKey, JFrame owner) {
3434         final int msgWidth = 50;
3435         JDialog d = new JDialog(owner);
3436         initDialog(d, uiKey);
3437         d.setTitle(getI18NString(uiKey + ".title"));
3438 
3439         JProgressBar pb = new JProgressBar(SwingConstants.HORIZONTAL);
3440         pb.setName(uiKey);
3441         pb.setIndeterminate(true);
3442         pb.setBorderPainted(true);
3443         pb.setPreferredSize(new Dimension(Math.round(2.5f * DOTS_PER_INCH),
3444                                 15));
3445 
3446         JPanel body = createPanel(uiKey, new GridBagLayout(), false);
3447         GridBagConstraints gbc = new GridBagConstraints();
3448         gbc.fill = GridBagConstraints.NONE;
3449         gbc.anchor = GridBagConstraints.CENTER;
3450         gbc.insets.left = 12;   // JL&F spacing
3451         gbc.insets.right = 12;  // JL&F spacing
3452         gbc.insets.top = 12;    // JL&F spacing
3453 
3454         gbc.gridy = 0;
3455         gbc.weightx = 0;
3456 
3457         JTextArea msg = createLocalizedMessageArea(uiKey,
3458                                     getI18NString(uiKey + ".txt"),
3459                                     false);
3460         // uif sets the size, but too large for this dialog
3461         msg.setSize(new Dimension(Math.round(4.0f * DOTS_PER_INCH),
3462                         Integer.MAX_VALUE));
3463         body.add(msg, gbc);
3464 
3465         // add progress bar
3466         gbc.gridy = 1;
3467         gbc.insets.top = 11;    // JL&F spacing
3468         gbc.insets.bottom = 12; // JL&F spacing
3469         body.add(pb, gbc);
3470 
3471         d.setContentPane(body);
3472         d.pack();
3473 
3474         d.setLocationRelativeTo(owner);
3475         return d;
3476     }
3477 
3478     /**
3479      * Configure a dialog with accessibility information.
3480      * <table>
3481      * <tr><td><i>uiKey</i>.desc <td>accessible description of the dialog
3482      * <tr><td><i>uiKey</i>.name <td>accessible name of the dialog
3483      * <tr><td><i>uiKey</i>.root <td>component name for the root pane of the
3484      *          dialog
3485      * </table>
3486      * @param d the dialog to upgrade
3487      * @param uiKey Key to retrieve the new properties with
3488      */
3489     public void initDialog(JDialog d, String uiKey) {
3490         d.setName(uiKey);
3491         setAccessibleInfo(d, uiKey);
3492         d.setLocationRelativeTo(d.getParent());
3493 
3494         JRootPane root = d.getRootPane();
3495         root.setName(uiKey + ".root");
3496         AccessibleContext ac = d.getAccessibleContext();
3497         AccessibleContext r_ac = root.getAccessibleContext();
3498         r_ac.setAccessibleName(ac.getAccessibleName());
3499         r_ac.setAccessibleDescription(ac.getAccessibleDescription());
3500     }
3501 
3502     /**
3503      * Configure a frame with accessibility information and an icon.
3504      * <table>
3505      * <tr><td><i>uiKey</i>.desc <td>accessible description of the frame
3506      * <tr><td><i>uiKey</i>.name <td>accessible name of the frame
3507      * <tr><td><i>uiKey</i>.root <td>component name for the root pane of the
3508      *          frame
3509      * </table>
3510      * @param d the frame to upgrade
3511      * @param uiKey Key to retrieve the new properties with
3512      */
3513     public void initFrame(JFrame d, String uiKey) {
3514         d.setName(uiKey);
3515         setAccessibleInfo(d, uiKey);
3516         d.setLocationRelativeTo(d.getParent());
3517 
3518         d.setIconImage(createImage("images/jticon.gif"));
3519 
3520         JRootPane root = d.getRootPane();
3521         root.setName(uiKey + ".root");
3522         AccessibleContext ac = d.getAccessibleContext();
3523         AccessibleContext r_ac = root.getAccessibleContext();
3524         r_ac.setAccessibleName(ac.getAccessibleName());
3525         r_ac.setAccessibleDescription(ac.getAccessibleDescription());
3526     }
3527 
3528 
3529     //----------------------------------------------------------------------------
3530 
3531     /**
3532      * Dispose of any owned resources.
3533      */
3534     public void dispose() {
3535         clientClass = null;
3536         parent = null;
3537     }
3538 
3539     //----------------------------------------------------------------------------
3540 
3541     private static Font baseFont = new JLabel().getFont();
3542 
3543     private static final ActionListener closeListener = new ActionListener() {
3544             public void actionPerformed(ActionEvent e) {
3545                 Component src = (Component) (e.getSource());
3546                 for (Container p = src.getParent(); p != null; p = p.getParent()) {
3547                     if (p instanceof JInternalFrame || p instanceof Window) {
3548                         p.setVisible(false);
3549                         return;
3550                     }
3551                 }
3552             }
3553         };
3554 
3555     private Class<?> clientClass;
3556     private Component parent;
3557     private I18NResourceBundle i18n;
3558     private HelpBroker helpBroker;
3559 
3560     private static I18NResourceBundle local_i18n = I18NResourceBundle.getBundleForClass(UIFactory.class);
3561     private static final int DOTS_PER_INCH = Toolkit.getDefaultToolkit().getScreenResolution();
3562 
3563     /**
3564      * Extension to the UIFactory that allows to use more than one resource
3565      * bundle. All methods accessing the resource bundle are overridden to
3566      * search for a resource in the alternative bundle first, and, if not found,
3567      * look up it in the original one.
3568      * <b>
3569      * This class might be helpful, when a component extends another components
3570      * from a different package.
3571      */
3572     public static class UIFactoryExt extends UIFactory {
3573         private I18NResourceBundle i18n_alt;
3574         private Class<?> altClass;
3575 
3576         public UIFactoryExt(UIFactory uif, Class<?> altClass) {
3577             super(uif.clientClass, uif.parent, uif.helpBroker);
3578             i18n_alt = I18NResourceBundle.getBundleForClass(altClass);
3579             this.altClass = altClass;
3580         }
3581 
3582         @Override
3583         public Color getI18NColor(String key) {
3584             if (!hasKey(i18n_alt,key)) {
3585                 return super.getI18NColor(key);
3586             }
3587             String value = i18n_alt.getString(key + ".clr");
3588             try {
3589                 if (value != null)
3590                     return Color.decode(value);
3591             }
3592             catch (Exception e) {
3593                 // ignore
3594             }
3595             return Color.BLACK;
3596 
3597         }
3598 
3599         @Override
3600         public String getI18NString(String key) {
3601             if (hasKey(i18n_alt,key)) {
3602                 return i18n_alt.getString(key);
3603             } else {
3604                 return super.getI18NString(key);
3605             }
3606         }
3607 
3608         @Override
3609         public String getI18NString(String key, Object arg) {
3610             if (hasKey(i18n_alt,key)) {
3611                 return i18n_alt.getString(key, arg);
3612             } else {
3613                 return super.getI18NString(key, arg);
3614             }
3615         }
3616 
3617         @Override
3618         public String getI18NString(String key, Object[] args) {
3619             if (hasKey(i18n_alt,key)) {
3620                 return i18n_alt.getString(key, args);
3621             } else {
3622                 return super.getI18NString(key, args);
3623             }
3624         }
3625 
3626         @Override
3627         public URL getIconURL(String uiKey) {
3628             String r = getI18NString(uiKey + ".icon");
3629 
3630             URL url = altClass.getResource(r);
3631 
3632             if (url == null)
3633                 url = super.getIconURL(uiKey);
3634 
3635             return url;
3636         }
3637 
3638         /**
3639          * It would be much better to use containsKey() instead, but
3640          * it's available since 1.6
3641          */
3642         static boolean hasKey(ResourceBundle rb, String key) {
3643             Enumeration<String> keys = rb.getKeys();
3644             if (keys == null || key == null) {
3645                 return false;
3646             }
3647             while(keys.hasMoreElements()) {
3648                 if (key.equals(keys.nextElement())) {
3649                     return true;
3650                 }
3651             }
3652             return false;
3653         }
3654     }
3655 }