1 /*
   2  *
   3  * Copyright (c) 2007, 2014, Oracle and/or its affiliates. All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  *
   9  *   - Redistributions of source code must retain the above copyright
  10  *     notice, this list of conditions and the following disclaimer.
  11  *
  12  *   - Redistributions in binary form must reproduce the above copyright
  13  *     notice, this list of conditions and the following disclaimer in the
  14  *     documentation and/or other materials provided with the distribution.
  15  *
  16  *   - Neither the name of Oracle nor the names of its
  17  *     contributors may be used to endorse or promote products derived
  18  *     from this software without specific prior written permission.
  19  *
  20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31  */
  32 
  33 import javax.swing.*;
  34 import javax.swing.event.*;
  35 import javax.swing.border.*;
  36 
  37 import javax.swing.plaf.metal.MetalTheme;
  38 import javax.swing.plaf.metal.OceanTheme;
  39 import javax.swing.plaf.metal.DefaultMetalTheme;
  40 import javax.swing.plaf.metal.MetalLookAndFeel;
  41 
  42 import java.lang.reflect.*;
  43 import java.awt.*;
  44 import java.awt.event.*;
  45 import java.util.*;
  46 
  47 /**
  48  * A demo that shows all of the Swing components.
  49  *
  50  * @author Jeff Dinkins
  51  */
  52 public class SwingSet2 extends JPanel {
  53 
  54     String[] demos = {
  55       "ButtonDemo",
  56       "ColorChooserDemo",
  57       "ComboBoxDemo",
  58       "FileChooserDemo",
  59       "HtmlDemo",
  60       "ListDemo",
  61       "OptionPaneDemo",
  62       "ProgressBarDemo",
  63       "ScrollPaneDemo",
  64       "SliderDemo",
  65       "SplitPaneDemo",
  66       "TabbedPaneDemo",
  67       "TableDemo",
  68       "ToolTipDemo",
  69       "TreeDemo"
  70     };
  71 
  72     void loadDemos() {
  73         for(int i = 0; i < demos.length;) {
  74             if(isApplet() && demos[i].equals("FileChooserDemo")) {
  75                // don't load the file chooser demo if we are
  76                // an applet
  77             } else {
  78                loadDemo(demos[i]);
  79             }
  80             i++;
  81         }
  82     }
  83 
  84     // The current Look & Feel
  85     private static LookAndFeelData currentLookAndFeel;
  86     private static LookAndFeelData[] lookAndFeelData;
  87     // List of demos
  88     private ArrayList<DemoModule> demosList = new ArrayList<DemoModule>();
  89 
  90     // The preferred size of the demo
  91     private static final int PREFERRED_WIDTH = 720;
  92     private static final int PREFERRED_HEIGHT = 640;
  93 
  94     // Box spacers
  95     private Dimension HGAP = new Dimension(1,5);
  96     private Dimension VGAP = new Dimension(5,1);
  97 
  98     // A place to hold on to the visible demo
  99     private DemoModule currentDemo = null;
 100     private JPanel demoPanel = null;
 101 
 102     // About Box
 103     private JDialog aboutBox = null;
 104 
 105     // Status Bar
 106     private JTextField statusField = null;
 107 
 108     // Tool Bar
 109     private ToggleButtonToolBar toolbar = null;
 110     private ButtonGroup toolbarGroup = new ButtonGroup();
 111 
 112     // Menus
 113     private JMenuBar menuBar = null;
 114     private JMenu lafMenu = null;
 115     private JMenu themesMenu = null;
 116     private JMenu audioMenu = null;
 117     private JMenu optionsMenu = null;
 118     private ButtonGroup lafMenuGroup = new ButtonGroup();
 119     private ButtonGroup themesMenuGroup = new ButtonGroup();
 120     private ButtonGroup audioMenuGroup = new ButtonGroup();
 121 
 122     // Popup menu
 123     private JPopupMenu popupMenu = null;
 124     private ButtonGroup popupMenuGroup = new ButtonGroup();
 125 
 126     // Used only if swingset is an application
 127     private JFrame frame = null;
 128 
 129     // Used only if swingset is an applet
 130     private SwingSet2Applet applet = null;
 131 
 132     // To debug or not to debug, that is the question
 133     private boolean DEBUG = true;
 134     private int debugCounter = 0;
 135 
 136     // The tab pane that holds the demo
 137     private JTabbedPane tabbedPane = null;
 138 
 139     private JEditorPane demoSrcPane = null;
 140 
 141 
 142     // contentPane cache, saved from the applet or application frame
 143     Container contentPane = null;
 144 
 145 
 146     // number of swingsets - for multiscreen
 147     // keep track of the number of SwingSets created - we only want to exit
 148     // the program when the last one has been closed.
 149     private static int numSSs = 0;
 150     private static Vector<SwingSet2> swingSets = new Vector<SwingSet2>();
 151 
 152     private boolean dragEnabled = false;
 153 
 154     public SwingSet2(SwingSet2Applet applet) {
 155         this(applet, null);
 156     }
 157 
 158     /**
 159      * SwingSet2 Constructor
 160      */
 161     public SwingSet2(SwingSet2Applet applet, GraphicsConfiguration gc) {
 162 
 163         // Note that applet may be null if this is started as an application
 164         this.applet = applet;
 165 
 166         String lafClassName = UIManager.getLookAndFeel().getClass().getName();
 167         lookAndFeelData = getInstalledLookAndFeelData();
 168         currentLookAndFeel = Arrays.stream(lookAndFeelData)
 169                 .filter(laf -> lafClassName.equals(laf.className))
 170                 .findFirst().get();
 171 
 172         if (!isApplet()) {
 173             frame = createFrame(gc);
 174         }
 175 
 176         // set the layout
 177         setLayout(new BorderLayout());
 178 
 179         // set the preferred size of the demo
 180         setPreferredSize(new Dimension(PREFERRED_WIDTH,PREFERRED_HEIGHT));
 181 
 182         initializeDemo();
 183         preloadFirstDemo();
 184 
 185         showSwingSet2();
 186 
 187         // Start loading the rest of the demo in the background
 188         DemoLoadThread demoLoader = new DemoLoadThread(this);
 189         demoLoader.start();
 190     }
 191 
 192 
 193     /**
 194      * SwingSet2 Main. Called only if we're an application, not an applet.
 195      */
 196     public static void main(final String[] args) {
 197         // must run in EDT when constructing the GUI components
 198         SwingUtilities.invokeLater(() -> {
 199             // Create SwingSet on the default monitor
 200             UIManager.put("swing.boldMetal", Boolean.FALSE);
 201             SwingSet2 swingset = new SwingSet2(null, GraphicsEnvironment.
 202                                          getLocalGraphicsEnvironment().
 203                                          getDefaultScreenDevice().
 204                                          getDefaultConfiguration());
 205         });
 206     }
 207 
 208     // *******************************************************
 209     // *************** Demo Loading Methods ******************
 210     // *******************************************************
 211 
 212 
 213 
 214     public void initializeDemo() {
 215         JPanel top = new JPanel();
 216         top.setLayout(new BorderLayout());
 217         add(top, BorderLayout.NORTH);
 218 
 219         menuBar = createMenus();
 220 
 221     if (isApplet()) {
 222         applet.setJMenuBar(menuBar);
 223     } else {
 224         frame.setJMenuBar(menuBar);
 225     }
 226 
 227         // creates popup menu accessible via keyboard
 228         popupMenu = createPopupMenu();
 229 
 230         ToolBarPanel toolbarPanel = new ToolBarPanel();
 231         toolbarPanel.setLayout(new BorderLayout());
 232         toolbar = new ToggleButtonToolBar();
 233         toolbarPanel.add(toolbar, BorderLayout.CENTER);
 234         top.add(toolbarPanel, BorderLayout.SOUTH);
 235         toolbarPanel.addContainerListener(toolbarPanel);
 236 
 237         tabbedPane = new JTabbedPane();
 238         add(tabbedPane, BorderLayout.CENTER);
 239         tabbedPane.getModel().addChangeListener(new TabListener());
 240 
 241         statusField = new JTextField("");
 242         statusField.setEditable(false);
 243         add(statusField, BorderLayout.SOUTH);
 244 
 245         demoPanel = new JPanel();
 246         demoPanel.setLayout(new BorderLayout());
 247         demoPanel.setBorder(new EtchedBorder());
 248         tabbedPane.addTab("Hi There!", demoPanel);
 249 
 250         // Add html src code viewer
 251         demoSrcPane = new JEditorPane("text/html", getString("SourceCode.loading"));
 252         demoSrcPane.setEditable(false);
 253 
 254         JScrollPane scroller = new JScrollPane();
 255         scroller.getViewport().add(demoSrcPane);
 256 
 257         tabbedPane.addTab(
 258             getString("TabbedPane.src_label"),
 259             null,
 260             scroller,
 261             getString("TabbedPane.src_tooltip")
 262         );
 263     }
 264 
 265     DemoModule currentTabDemo = null;
 266     class TabListener implements ChangeListener {
 267         public void stateChanged(ChangeEvent e) {
 268             SingleSelectionModel model = (SingleSelectionModel) e.getSource();
 269             boolean srcSelected = model.getSelectedIndex() == 1;
 270             if(currentTabDemo != currentDemo && demoSrcPane != null && srcSelected) {
 271                 demoSrcPane.setText(getString("SourceCode.loading"));
 272                 repaint();
 273             }
 274             if(currentTabDemo != currentDemo && srcSelected) {
 275                 currentTabDemo = currentDemo;
 276                 setSourceCode(currentDemo);
 277             }
 278         }
 279     }
 280 
 281 
 282     /**
 283      * Create menus
 284      */
 285     public JMenuBar createMenus() {
 286         JMenuItem mi;
 287         // ***** create the menubar ****
 288         JMenuBar menuBar = new JMenuBar();
 289         menuBar.getAccessibleContext().setAccessibleName(
 290             getString("MenuBar.accessible_description"));
 291 
 292         // ***** create File menu
 293         JMenu fileMenu = (JMenu) menuBar.add(new JMenu(getString("FileMenu.file_label")));
 294         fileMenu.setMnemonic(getMnemonic("FileMenu.file_mnemonic"));
 295         fileMenu.getAccessibleContext().setAccessibleDescription(getString("FileMenu.accessible_description"));
 296 
 297         createMenuItem(fileMenu, "FileMenu.about_label", "FileMenu.about_mnemonic",
 298                        "FileMenu.about_accessible_description", new AboutAction(this));
 299 
 300         fileMenu.addSeparator();
 301 
 302         createMenuItem(fileMenu, "FileMenu.open_label", "FileMenu.open_mnemonic",
 303                        "FileMenu.open_accessible_description", null);
 304 
 305         createMenuItem(fileMenu, "FileMenu.save_label", "FileMenu.save_mnemonic",
 306                        "FileMenu.save_accessible_description", null);
 307 
 308         createMenuItem(fileMenu, "FileMenu.save_as_label", "FileMenu.save_as_mnemonic",
 309                        "FileMenu.save_as_accessible_description", null);
 310 
 311 
 312         if(!isApplet()) {
 313             fileMenu.addSeparator();
 314 
 315             createMenuItem(fileMenu, "FileMenu.exit_label", "FileMenu.exit_mnemonic",
 316                            "FileMenu.exit_accessible_description", new ExitAction(this)
 317             );
 318         }
 319 
 320         // Create these menu items for the first SwingSet only.
 321         if (numSSs == 0) {
 322         // ***** create laf switcher menu
 323         lafMenu = (JMenu) menuBar.add(new JMenu(getString("LafMenu.laf_label")));
 324         lafMenu.setMnemonic(getMnemonic("LafMenu.laf_mnemonic"));
 325         lafMenu.getAccessibleContext().setAccessibleDescription(
 326             getString("LafMenu.laf_accessible_description"));
 327 
 328         for (LookAndFeelData lafData : lookAndFeelData) {
 329             mi = createLafMenuItem(lafMenu, lafData);
 330             mi.setSelected(lafData.equals(currentLookAndFeel));
 331         }
 332 
 333         // ***** create themes menu
 334         themesMenu = (JMenu) menuBar.add(new JMenu(getString("ThemesMenu.themes_label")));
 335         themesMenu.setMnemonic(getMnemonic("ThemesMenu.themes_mnemonic"));
 336         themesMenu.getAccessibleContext().setAccessibleDescription(
 337             getString("ThemesMenu.themes_accessible_description"));
 338 
 339         // ***** create the audio submenu under the theme menu
 340         audioMenu = (JMenu) themesMenu.add(new JMenu(getString("AudioMenu.audio_label")));
 341         audioMenu.setMnemonic(getMnemonic("AudioMenu.audio_mnemonic"));
 342         audioMenu.getAccessibleContext().setAccessibleDescription(
 343             getString("AudioMenu.audio_accessible_description"));
 344 
 345         createAudioMenuItem(audioMenu, "AudioMenu.on_label",
 346                             "AudioMenu.on_mnemonic",
 347                             "AudioMenu.on_accessible_description",
 348                             new OnAudioAction(this));
 349 
 350         mi = createAudioMenuItem(audioMenu, "AudioMenu.default_label",
 351                                  "AudioMenu.default_mnemonic",
 352                                  "AudioMenu.default_accessible_description",
 353                                  new DefaultAudioAction(this));
 354         mi.setSelected(true); // This is the default feedback setting
 355 
 356         createAudioMenuItem(audioMenu, "AudioMenu.off_label",
 357                             "AudioMenu.off_mnemonic",
 358                             "AudioMenu.off_accessible_description",
 359                             new OffAudioAction(this));
 360 
 361 
 362         // ***** create the font submenu under the theme menu
 363         JMenu fontMenu = (JMenu) themesMenu.add(new JMenu(getString("FontMenu.fonts_label")));
 364         fontMenu.setMnemonic(getMnemonic("FontMenu.fonts_mnemonic"));
 365         fontMenu.getAccessibleContext().setAccessibleDescription(
 366             getString("FontMenu.fonts_accessible_description"));
 367         ButtonGroup fontButtonGroup = new ButtonGroup();
 368         mi = createButtonGroupMenuItem(fontMenu, "FontMenu.plain_label",
 369                 "FontMenu.plain_mnemonic",
 370                 "FontMenu.plain_accessible_description",
 371                 new ChangeFontAction(this, true), fontButtonGroup);
 372         mi.setSelected(true);
 373         mi = createButtonGroupMenuItem(fontMenu, "FontMenu.bold_label",
 374                 "FontMenu.bold_mnemonic",
 375                 "FontMenu.bold_accessible_description",
 376                 new ChangeFontAction(this, false), fontButtonGroup);
 377 
 378 
 379 
 380         // *** now back to adding color/font themes to the theme menu
 381         mi = createThemesMenuItem(themesMenu, "ThemesMenu.ocean_label",
 382                                               "ThemesMenu.ocean_mnemonic",
 383                                               "ThemesMenu.ocean_accessible_description",
 384                                               new OceanTheme());
 385         mi.setSelected(true); // This is the default theme
 386 
 387         createThemesMenuItem(themesMenu, "ThemesMenu.steel_label",
 388                              "ThemesMenu.steel_mnemonic",
 389                              "ThemesMenu.steel_accessible_description",
 390                              new DefaultMetalTheme());
 391 
 392         createThemesMenuItem(themesMenu, "ThemesMenu.aqua_label", "ThemesMenu.aqua_mnemonic",
 393                        "ThemesMenu.aqua_accessible_description", new AquaTheme());
 394 
 395         createThemesMenuItem(themesMenu, "ThemesMenu.charcoal_label", "ThemesMenu.charcoal_mnemonic",
 396                        "ThemesMenu.charcoal_accessible_description", new CharcoalTheme());
 397 
 398         createThemesMenuItem(themesMenu, "ThemesMenu.contrast_label", "ThemesMenu.contrast_mnemonic",
 399                        "ThemesMenu.contrast_accessible_description", new ContrastTheme());
 400 
 401         createThemesMenuItem(themesMenu, "ThemesMenu.emerald_label", "ThemesMenu.emerald_mnemonic",
 402                        "ThemesMenu.emerald_accessible_description", new EmeraldTheme());
 403 
 404         createThemesMenuItem(themesMenu, "ThemesMenu.ruby_label", "ThemesMenu.ruby_mnemonic",
 405                        "ThemesMenu.ruby_accessible_description", new RubyTheme());
 406 
 407         // Enable theme menu based on L&F
 408         themesMenu.setEnabled("Metal".equals(currentLookAndFeel.name));
 409 
 410         // ***** create the options menu
 411         optionsMenu = (JMenu)menuBar.add(
 412             new JMenu(getString("OptionsMenu.options_label")));
 413         optionsMenu.setMnemonic(getMnemonic("OptionsMenu.options_mnemonic"));
 414         optionsMenu.getAccessibleContext().setAccessibleDescription(
 415             getString("OptionsMenu.options_accessible_description"));
 416 
 417         // ***** create tool tip submenu item.
 418         mi = createCheckBoxMenuItem(optionsMenu, "OptionsMenu.tooltip_label",
 419                 "OptionsMenu.tooltip_mnemonic",
 420                 "OptionsMenu.tooltip_accessible_description",
 421                 new ToolTipAction());
 422         mi.setSelected(true);
 423 
 424         // ***** create drag support submenu item.
 425         createCheckBoxMenuItem(optionsMenu, "OptionsMenu.dragEnabled_label",
 426                 "OptionsMenu.dragEnabled_mnemonic",
 427                 "OptionsMenu.dragEnabled_accessible_description",
 428                 new DragSupportAction());
 429 
 430         }
 431 
 432 
 433         // ***** create the multiscreen menu, if we have multiple screens
 434     if (!isApplet()) {
 435         GraphicsDevice[] screens = GraphicsEnvironment.
 436                                     getLocalGraphicsEnvironment().
 437                                     getScreenDevices();
 438         if (screens.length > 1) {
 439 
 440             JMenu multiScreenMenu = (JMenu) menuBar.add(new JMenu(
 441                                      getString("MultiMenu.multi_label")));
 442 
 443             multiScreenMenu.setMnemonic(getMnemonic("MultiMenu.multi_mnemonic"));
 444             multiScreenMenu.getAccessibleContext().setAccessibleDescription(
 445              getString("MultiMenu.multi_accessible_description"));
 446 
 447             createMultiscreenMenuItem(multiScreenMenu, MultiScreenAction.ALL_SCREENS);
 448             for (int i = 0; i < screens.length; i++) {
 449                 createMultiscreenMenuItem(multiScreenMenu, i);
 450             }
 451         }
 452     }
 453 
 454         return menuBar;
 455     }
 456 
 457     /**
 458      * Create a checkbox menu menu item
 459      */
 460     private JMenuItem createCheckBoxMenuItem(JMenu menu, String label,
 461                                              String mnemonic,
 462                                              String accessibleDescription,
 463                                              Action action) {
 464         JCheckBoxMenuItem mi = (JCheckBoxMenuItem)menu.add(
 465                 new JCheckBoxMenuItem(getString(label)));
 466         mi.setMnemonic(getMnemonic(mnemonic));
 467         mi.getAccessibleContext().setAccessibleDescription(getString(
 468                 accessibleDescription));
 469         mi.addActionListener(action);
 470         return mi;
 471     }
 472 
 473     /**
 474      * Create a radio button menu menu item for items that are part of a
 475      * button group.
 476      */
 477     private JMenuItem createButtonGroupMenuItem(JMenu menu, String label,
 478                                                 String mnemonic,
 479                                                 String accessibleDescription,
 480                                                 Action action,
 481                                                 ButtonGroup buttonGroup) {
 482         JRadioButtonMenuItem mi = (JRadioButtonMenuItem)menu.add(
 483                 new JRadioButtonMenuItem(getString(label)));
 484         buttonGroup.add(mi);
 485         mi.setMnemonic(getMnemonic(mnemonic));
 486         mi.getAccessibleContext().setAccessibleDescription(getString(
 487                 accessibleDescription));
 488         mi.addActionListener(action);
 489         return mi;
 490     }
 491 
 492     /**
 493      * Create the theme's audio submenu
 494      */
 495     public JMenuItem createAudioMenuItem(JMenu menu, String label,
 496                                          String mnemonic,
 497                                          String accessibleDescription,
 498                                          Action action) {
 499         JRadioButtonMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(getString(label)));
 500         audioMenuGroup.add(mi);
 501         mi.setMnemonic(getMnemonic(mnemonic));
 502         mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
 503         mi.addActionListener(action);
 504 
 505         return mi;
 506     }
 507 
 508     /**
 509      * Creates a generic menu item
 510      */
 511     public JMenuItem createMenuItem(JMenu menu, String label, String mnemonic,
 512                                String accessibleDescription, Action action) {
 513         JMenuItem mi = (JMenuItem) menu.add(new JMenuItem(getString(label)));
 514         mi.setMnemonic(getMnemonic(mnemonic));
 515         mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
 516         mi.addActionListener(action);
 517         if(action == null) {
 518             mi.setEnabled(false);
 519         }
 520         return mi;
 521     }
 522 
 523     /**
 524      * Creates a JRadioButtonMenuItem for the Themes menu
 525      */
 526     public JMenuItem createThemesMenuItem(JMenu menu, String label, String mnemonic,
 527                                String accessibleDescription, MetalTheme theme) {
 528         JRadioButtonMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(getString(label)));
 529         themesMenuGroup.add(mi);
 530         mi.setMnemonic(getMnemonic(mnemonic));
 531         mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
 532         mi.addActionListener(new ChangeThemeAction(this, theme));
 533 
 534         return mi;
 535     }
 536 
 537     /**
 538      * Creates a JRadioButtonMenuItem for the Look and Feel menu
 539      */
 540     public JMenuItem createLafMenuItem(JMenu menu, LookAndFeelData lafData) {
 541         JMenuItem mi = menu.add(new JRadioButtonMenuItem(lafData.label));
 542         lafMenuGroup.add(mi);
 543         mi.setMnemonic(lafData.mnemonic);
 544         mi.getAccessibleContext().setAccessibleDescription(lafData.accDescription);
 545         mi.addActionListener(new ChangeLookAndFeelAction(this, lafData));
 546         return mi;
 547     }
 548 
 549     /**
 550      * Creates a multi-screen menu item
 551      */
 552     public JMenuItem createMultiscreenMenuItem(JMenu menu, int screen) {
 553         JMenuItem mi = null;
 554         if (screen == MultiScreenAction.ALL_SCREENS) {
 555             mi = (JMenuItem) menu.add(new JMenuItem(getString("MultiMenu.all_label")));
 556             mi.setMnemonic(getMnemonic("MultiMenu.all_mnemonic"));
 557             mi.getAccessibleContext().setAccessibleDescription(getString(
 558                                                                  "MultiMenu.all_accessible_description"));
 559         }
 560         else {
 561             mi = (JMenuItem) menu.add(new JMenuItem(getString("MultiMenu.single_label") + " " +
 562                                                                                                  screen));
 563             mi.setMnemonic(KeyEvent.VK_0 + screen);
 564             mi.getAccessibleContext().setAccessibleDescription(getString(
 565                                                "MultiMenu.single_accessible_description") + " " + screen);
 566 
 567         }
 568         mi.addActionListener(new MultiScreenAction(this, screen));
 569         return mi;
 570     }
 571 
 572     public JPopupMenu createPopupMenu() {
 573         JPopupMenu popup = new JPopupMenu("JPopupMenu demo");
 574 
 575         for (LookAndFeelData lafData : lookAndFeelData) {
 576             createPopupMenuItem(popup, lafData);
 577         }
 578 
 579         // register key binding to activate popup menu
 580         InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
 581         map.put(KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.SHIFT_MASK),
 582                 "postMenuAction");
 583         map.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTEXT_MENU, 0), "postMenuAction");
 584         getActionMap().put("postMenuAction", new ActivatePopupMenuAction(this, popup));
 585 
 586         return popup;
 587     }
 588 
 589     /**
 590      * Creates a JMenuItem for the Look and Feel popup menu
 591      */
 592     public JMenuItem createPopupMenuItem(JPopupMenu menu, LookAndFeelData lafData) {
 593         JMenuItem mi = menu.add(new JMenuItem(lafData.label));
 594         popupMenuGroup.add(mi);
 595         mi.setMnemonic(lafData.mnemonic);
 596         mi.getAccessibleContext().setAccessibleDescription(lafData.accDescription);
 597         mi.addActionListener(new ChangeLookAndFeelAction(this, lafData));
 598         return mi;
 599     }
 600 
 601 
 602     /**
 603      * Load the first demo. This is done separately from the remaining demos
 604      * so that we can get SwingSet2 up and available to the user quickly.
 605      */
 606     public void preloadFirstDemo() {
 607         DemoModule demo = addDemo(new InternalFrameDemo(this));
 608         setDemo(demo);
 609     }
 610 
 611 
 612     /**
 613      * Add a demo to the toolbar
 614      */
 615     public DemoModule addDemo(DemoModule demo) {
 616         demosList.add(demo);
 617         if (dragEnabled) {
 618             demo.updateDragEnabled(true);
 619         }
 620         // do the following on the gui thread
 621         SwingUtilities.invokeLater(new SwingSetRunnable(this, demo) {
 622             public void run() {
 623                 SwitchToDemoAction action = new SwitchToDemoAction(swingset, (DemoModule) obj);
 624                 JToggleButton tb = swingset.getToolBar().addToggleButton(action);
 625                 swingset.getToolBarGroup().add(tb);
 626                 if(swingset.getToolBarGroup().getSelection() == null) {
 627                     tb.setSelected(true);
 628                 }
 629                 tb.setText(null);
 630                 tb.setToolTipText(((DemoModule)obj).getToolTip());
 631 
 632                 if(demos[demos.length-1].equals(obj.getClass().getName())) {
 633                     setStatus(getString("Status.popupMenuAccessible"));
 634                 }
 635 
 636             }
 637         });
 638         return demo;
 639     }
 640 
 641 
 642     /**
 643      * Sets the current demo
 644      */
 645     public void setDemo(DemoModule demo) {
 646         currentDemo = demo;
 647 
 648         // Ensure panel's UI is current before making visible
 649         JComponent currentDemoPanel = demo.getDemoPanel();
 650         SwingUtilities.updateComponentTreeUI(currentDemoPanel);
 651 
 652         demoPanel.removeAll();
 653         demoPanel.add(currentDemoPanel, BorderLayout.CENTER);
 654 
 655         tabbedPane.setSelectedIndex(0);
 656         tabbedPane.setTitleAt(0, demo.getName());
 657         tabbedPane.setToolTipTextAt(0, demo.getToolTip());
 658     }
 659 
 660 
 661     /**
 662      * Bring up the SwingSet2 demo by showing the frame (only
 663      * applicable if coming up as an application, not an applet);
 664      */
 665     public void showSwingSet2() {
 666         if(!isApplet() && getFrame() != null) {
 667             // put swingset in a frame and show it
 668             JFrame f = getFrame();
 669             f.setTitle(getString("Frame.title"));
 670             f.getContentPane().add(this, BorderLayout.CENTER);
 671             f.pack();
 672 
 673             Rectangle screenRect = f.getGraphicsConfiguration().getBounds();
 674             Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(
 675                     f.getGraphicsConfiguration());
 676 
 677             // Make sure we don't place the demo off the screen.
 678             int centerWidth = screenRect.width < f.getSize().width ?
 679                     screenRect.x :
 680                     screenRect.x + screenRect.width/2 - f.getSize().width/2;
 681             int centerHeight = screenRect.height < f.getSize().height ?
 682                     screenRect.y :
 683                     screenRect.y + screenRect.height/2 - f.getSize().height/2;
 684 
 685             centerHeight = centerHeight < screenInsets.top ?
 686                     screenInsets.top : centerHeight;
 687 
 688             f.setLocation(centerWidth, centerHeight);
 689             f.show();
 690             numSSs++;
 691             swingSets.add(this);
 692         }
 693     }
 694 
 695     // *******************************************************
 696     // ****************** Utility Methods ********************
 697     // *******************************************************
 698 
 699     /**
 700      * Loads a demo from a classname
 701      */
 702     void loadDemo(String classname) {
 703         setStatus(getString("Status.loading") + getString(classname + ".name"));
 704         DemoModule demo = null;
 705         try {
 706             Class demoClass = Class.forName(classname);
 707             Constructor demoConstructor = demoClass.getConstructor(new Class[]{SwingSet2.class});
 708             demo = (DemoModule) demoConstructor.newInstance(new Object[]{this});
 709             addDemo(demo);
 710         } catch (Exception e) {
 711             System.out.println("Error occurred loading demo: " + classname);
 712         }
 713     }
 714 
 715     /**
 716      * Determines if this is an applet or application
 717      */
 718     public boolean isApplet() {
 719         return (applet != null);
 720     }
 721 
 722     /**
 723      * Returns the applet instance
 724      */
 725     public SwingSet2Applet getApplet() {
 726         return applet;
 727     }
 728 
 729 
 730     /**
 731      * Returns the frame instance
 732      */
 733     public JFrame getFrame() {
 734         return frame;
 735     }
 736 
 737     /**
 738      * Returns the menubar
 739      */
 740     public JMenuBar getMenuBar() {
 741         return menuBar;
 742     }
 743 
 744     /**
 745      * Returns the toolbar
 746      */
 747     public ToggleButtonToolBar getToolBar() {
 748         return toolbar;
 749     }
 750 
 751     /**
 752      * Returns the toolbar button group
 753      */
 754     public ButtonGroup getToolBarGroup() {
 755         return toolbarGroup;
 756     }
 757 
 758     /**
 759      * Returns the content pane whether we're in an applet
 760      * or application
 761      */
 762     public Container getContentPane() {
 763         if(contentPane == null) {
 764             if(getFrame() != null) {
 765                 contentPane = getFrame().getContentPane();
 766             } else if (getApplet() != null) {
 767                 contentPane = getApplet().getContentPane();
 768             }
 769         }
 770         return contentPane;
 771     }
 772 
 773     /**
 774      * Create a frame for SwingSet2 to reside in if brought up
 775      * as an application.
 776      */
 777     public static JFrame createFrame(GraphicsConfiguration gc) {
 778         JFrame frame = new JFrame(gc);
 779         if (numSSs == 0) {
 780             frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 781         } else {
 782             WindowListener l = new WindowAdapter() {
 783                 public void windowClosing(WindowEvent e) {
 784                     numSSs--;
 785                     swingSets.remove(this);
 786                 }
 787             };
 788             frame.addWindowListener(l);
 789         }
 790         return frame;
 791     }
 792 
 793 
 794     /**
 795      * Set the status
 796      */
 797     public void setStatus(String s) {
 798         // do the following on the gui thread
 799         SwingUtilities.invokeLater(new SwingSetRunnable(this, s) {
 800             public void run() {
 801                 swingset.statusField.setText((String) obj);
 802             }
 803         });
 804     }
 805 
 806 
 807     /**
 808      * This method returns a string from the demo's resource bundle.
 809      */
 810     public static String getString(String key) {
 811         String value = null;
 812         try {
 813             value = TextAndMnemonicUtils.getTextAndMnemonicString(key);
 814         } catch (MissingResourceException e) {
 815             System.out.println("java.util.MissingResourceException: Couldn't find value for: " + key);
 816         }
 817         if(value == null) {
 818             value = "Could not find resource: " + key + "  ";
 819         }
 820         return value;
 821     }
 822 
 823     void setDragEnabled(boolean dragEnabled) {
 824         if (dragEnabled == this.dragEnabled) {
 825             return;
 826         }
 827 
 828         this.dragEnabled = dragEnabled;
 829 
 830         for (DemoModule dm : demosList) {
 831             dm.updateDragEnabled(dragEnabled);
 832         }
 833 
 834         demoSrcPane.setDragEnabled(dragEnabled);
 835     }
 836 
 837     boolean isDragEnabled() {
 838         return dragEnabled;
 839     }
 840 
 841 
 842     /**
 843      * Returns a mnemonic from the resource bundle. Typically used as
 844      * keyboard shortcuts in menu items.
 845      */
 846     public char getMnemonic(String key) {
 847         return (getString(key)).charAt(0);
 848     }
 849 
 850     /**
 851      * Creates an icon from an image contained in the "images" directory.
 852      */
 853     public ImageIcon createImageIcon(String filename, String description) {
 854         String path = "/resources/images/" + filename;
 855         return new ImageIcon(getClass().getResource(path));
 856     }
 857 
 858     /**
 859      * If DEBUG is defined, prints debug information out to std ouput.
 860      */
 861     public void debug(String s) {
 862         if(DEBUG) {
 863             System.out.println((debugCounter++) + ": " + s);
 864         }
 865     }
 866 
 867     /**
 868      * Stores the current L&F, and calls updateLookAndFeel, below
 869      */
 870     public void setLookAndFeel(LookAndFeelData laf) {
 871         if(!currentLookAndFeel.equals(laf)) {
 872             currentLookAndFeel = laf;
 873             /* The recommended way of synchronizing state between multiple
 874              * controls that represent the same command is to use Actions.
 875              * The code below is a workaround and will be replaced in future
 876              * version of SwingSet2 demo.
 877              */
 878             String lafName = laf.label;
 879             themesMenu.setEnabled(laf.name.equals("Metal"));
 880             updateLookAndFeel();
 881             for(int i=0;i<lafMenu.getItemCount();i++) {
 882                 JMenuItem item = lafMenu.getItem(i);
 883                 item.setSelected(item.getText().equals(lafName));
 884             }
 885         }
 886     }
 887 
 888     private void updateThisSwingSet() {
 889         if (isApplet()) {
 890             SwingUtilities.updateComponentTreeUI(getApplet());
 891         } else {
 892             JFrame frame = getFrame();
 893             if (frame == null) {
 894                 SwingUtilities.updateComponentTreeUI(this);
 895             } else {
 896                 SwingUtilities.updateComponentTreeUI(frame);
 897             }
 898         }
 899 
 900         SwingUtilities.updateComponentTreeUI(popupMenu);
 901         if (aboutBox != null) {
 902             SwingUtilities.updateComponentTreeUI(aboutBox);
 903         }
 904     }
 905 
 906     /**
 907      * Sets the current L&F on each demo module
 908      */
 909     public void updateLookAndFeel() {
 910         try {
 911             UIManager.setLookAndFeel(currentLookAndFeel.className);
 912             if (isApplet()) {
 913                 updateThisSwingSet();
 914             } else {
 915                 for (SwingSet2 ss : swingSets) {
 916                     ss.updateThisSwingSet();
 917                 }
 918             }
 919         } catch (Exception ex) {
 920             System.out.println("Failed loading L&F: " + currentLookAndFeel);
 921             System.out.println(ex);
 922         }
 923     }
 924 
 925     /**
 926      * Loads and puts the source code text into JEditorPane in the "Source Code" tab
 927      */
 928     public void setSourceCode(DemoModule demo) {
 929         // do the following on the gui thread
 930         SwingUtilities.invokeLater(new SwingSetRunnable(this, demo) {
 931             public void run() {
 932                 swingset.demoSrcPane.setText(((DemoModule)obj).getSourceCode());
 933                 swingset.demoSrcPane.setCaretPosition(0);
 934 
 935             }
 936         });
 937     }
 938 
 939     // *******************************************************
 940     // **************   ToggleButtonToolbar  *****************
 941     // *******************************************************
 942     static Insets zeroInsets = new Insets(1,1,1,1);
 943     protected class ToggleButtonToolBar extends JToolBar {
 944         public ToggleButtonToolBar() {
 945             super();
 946         }
 947 
 948         JToggleButton addToggleButton(Action a) {
 949             JToggleButton tb = new JToggleButton(
 950                 (String)a.getValue(Action.NAME),
 951                 (Icon)a.getValue(Action.SMALL_ICON)
 952             );
 953             tb.setMargin(zeroInsets);
 954             tb.setText(null);
 955             tb.setEnabled(a.isEnabled());
 956             tb.setToolTipText((String)a.getValue(Action.SHORT_DESCRIPTION));
 957             tb.setAction(a);
 958             add(tb);
 959             return tb;
 960         }
 961     }
 962 
 963     // *******************************************************
 964     // *********  ToolBar Panel / Docking Listener ***********
 965     // *******************************************************
 966     class ToolBarPanel extends JPanel implements ContainerListener {
 967 
 968         public boolean contains(int x, int y) {
 969             Component c = getParent();
 970             if (c != null) {
 971                 Rectangle r = c.getBounds();
 972                 return (x >= 0) && (x < r.width) && (y >= 0) && (y < r.height);
 973             }
 974             else {
 975                 return super.contains(x,y);
 976             }
 977         }
 978 
 979         public void componentAdded(ContainerEvent e) {
 980             Container c = e.getContainer().getParent();
 981             if (c != null) {
 982                 c.getParent().validate();
 983                 c.getParent().repaint();
 984             }
 985         }
 986 
 987         public void componentRemoved(ContainerEvent e) {
 988             Container c = e.getContainer().getParent();
 989             if (c != null) {
 990                 c.getParent().validate();
 991                 c.getParent().repaint();
 992             }
 993         }
 994     }
 995 
 996     // *******************************************************
 997     // ******************   Runnables  ***********************
 998     // *******************************************************
 999 
1000     /**
1001      * Generic SwingSet2 runnable. This is intended to run on the
1002      * AWT gui event thread so as not to muck things up by doing
1003      * gui work off the gui thread. Accepts a SwingSet2 and an Object
1004      * as arguments, which gives subtypes of this class the two
1005      * "must haves" needed in most runnables for this demo.
1006      */
1007     class SwingSetRunnable implements Runnable {
1008         protected SwingSet2 swingset;
1009         protected Object obj;
1010 
1011         public SwingSetRunnable(SwingSet2 swingset, Object obj) {
1012             this.swingset = swingset;
1013             this.obj = obj;
1014         }
1015 
1016         public void run() {
1017         }
1018     }
1019 
1020 
1021     // *******************************************************
1022     // ********************   Actions  ***********************
1023     // *******************************************************
1024 
1025     public class SwitchToDemoAction extends AbstractAction {
1026         SwingSet2 swingset;
1027         DemoModule demo;
1028 
1029         public SwitchToDemoAction(SwingSet2 swingset, DemoModule demo) {
1030             super(demo.getName(), demo.getIcon());
1031             this.swingset = swingset;
1032             this.demo = demo;
1033         }
1034 
1035         public void actionPerformed(ActionEvent e) {
1036             swingset.setDemo(demo);
1037         }
1038     }
1039 
1040     class OkAction extends AbstractAction {
1041         JDialog aboutBox;
1042 
1043         protected OkAction(JDialog aboutBox) {
1044             super("OkAction");
1045             this.aboutBox = aboutBox;
1046         }
1047 
1048         public void actionPerformed(ActionEvent e) {
1049             aboutBox.setVisible(false);
1050         }
1051     }
1052 
1053     class ChangeLookAndFeelAction extends AbstractAction {
1054         SwingSet2 swingset;
1055         LookAndFeelData lafData;
1056         protected ChangeLookAndFeelAction(SwingSet2 swingset, LookAndFeelData lafData) {
1057             super("ChangeTheme");
1058             this.swingset = swingset;
1059             this.lafData = lafData;
1060         }
1061 
1062         public void actionPerformed(ActionEvent e) {
1063             swingset.setLookAndFeel(lafData);
1064         }
1065     }
1066 
1067     class ActivatePopupMenuAction extends AbstractAction {
1068         SwingSet2 swingset;
1069         JPopupMenu popup;
1070         protected ActivatePopupMenuAction(SwingSet2 swingset, JPopupMenu popup) {
1071             super("ActivatePopupMenu");
1072             this.swingset = swingset;
1073             this.popup = popup;
1074         }
1075 
1076         public void actionPerformed(ActionEvent e) {
1077             Dimension invokerSize = getSize();
1078             Dimension popupSize = popup.getPreferredSize();
1079             popup.show(swingset, (invokerSize.width - popupSize.width) / 2,
1080                        (invokerSize.height - popupSize.height) / 2);
1081         }
1082     }
1083 
1084     // Turns on all possible auditory feedback
1085     class OnAudioAction extends AbstractAction {
1086         SwingSet2 swingset;
1087         protected OnAudioAction(SwingSet2 swingset) {
1088             super("Audio On");
1089             this.swingset = swingset;
1090         }
1091         public void actionPerformed(ActionEvent e) {
1092             UIManager.put("AuditoryCues.playList",
1093                           UIManager.get("AuditoryCues.allAuditoryCues"));
1094             swingset.updateLookAndFeel();
1095         }
1096     }
1097 
1098     // Turns on the default amount of auditory feedback
1099     class DefaultAudioAction extends AbstractAction {
1100         SwingSet2 swingset;
1101         protected DefaultAudioAction(SwingSet2 swingset) {
1102             super("Audio Default");
1103             this.swingset = swingset;
1104         }
1105         public void actionPerformed(ActionEvent e) {
1106             UIManager.put("AuditoryCues.playList",
1107                           UIManager.get("AuditoryCues.defaultCueList"));
1108             swingset.updateLookAndFeel();
1109         }
1110     }
1111 
1112     // Turns off all possible auditory feedback
1113     class OffAudioAction extends AbstractAction {
1114         SwingSet2 swingset;
1115         protected OffAudioAction(SwingSet2 swingset) {
1116             super("Audio Off");
1117             this.swingset = swingset;
1118         }
1119         public void actionPerformed(ActionEvent e) {
1120             UIManager.put("AuditoryCues.playList",
1121                           UIManager.get("AuditoryCues.noAuditoryCues"));
1122             swingset.updateLookAndFeel();
1123         }
1124     }
1125 
1126     // Turns on or off the tool tips for the demo.
1127     class ToolTipAction extends AbstractAction {
1128         protected ToolTipAction() {
1129             super("ToolTip Control");
1130         }
1131 
1132         public void actionPerformed(ActionEvent e) {
1133             boolean status = ((JCheckBoxMenuItem)e.getSource()).isSelected();
1134             ToolTipManager.sharedInstance().setEnabled(status);
1135         }
1136     }
1137 
1138     class DragSupportAction extends AbstractAction {
1139         protected DragSupportAction() {
1140             super("DragSupport Control");
1141         }
1142 
1143         public void actionPerformed(ActionEvent e) {
1144             boolean dragEnabled = ((JCheckBoxMenuItem)e.getSource()).isSelected();
1145             if (isApplet()) {
1146                 setDragEnabled(dragEnabled);
1147             } else {
1148                 for (SwingSet2 ss : swingSets) {
1149                     ss.setDragEnabled(dragEnabled);
1150                 }
1151             }
1152         }
1153     }
1154 
1155     class ChangeThemeAction extends AbstractAction {
1156         SwingSet2 swingset;
1157         MetalTheme theme;
1158         protected ChangeThemeAction(SwingSet2 swingset, MetalTheme theme) {
1159             super("ChangeTheme");
1160             this.swingset = swingset;
1161             this.theme = theme;
1162         }
1163 
1164         public void actionPerformed(ActionEvent e) {
1165             MetalLookAndFeel.setCurrentTheme(theme);
1166             swingset.updateLookAndFeel();
1167         }
1168     }
1169 
1170     class ExitAction extends AbstractAction {
1171         SwingSet2 swingset;
1172         protected ExitAction(SwingSet2 swingset) {
1173             super("ExitAction");
1174             this.swingset = swingset;
1175         }
1176 
1177         public void actionPerformed(ActionEvent e) {
1178             System.exit(0);
1179         }
1180     }
1181 
1182     class AboutAction extends AbstractAction {
1183         SwingSet2 swingset;
1184         protected AboutAction(SwingSet2 swingset) {
1185             super("AboutAction");
1186             this.swingset = swingset;
1187         }
1188 
1189         public void actionPerformed(ActionEvent e) {
1190             if(aboutBox == null) {
1191                 // JPanel panel = new JPanel(new BorderLayout());
1192                 JPanel panel = new AboutPanel(swingset);
1193                 panel.setLayout(new BorderLayout());
1194 
1195                 aboutBox = new JDialog(swingset.getFrame(), getString("AboutBox.title"), false);
1196                 aboutBox.setResizable(false);
1197                 aboutBox.getContentPane().add(panel, BorderLayout.CENTER);
1198 
1199                 // JButton button = new JButton(getString("AboutBox.ok_button_text"));
1200                 JPanel buttonpanel = new JPanel();
1201                 buttonpanel.setBorder(new javax.swing.border.EmptyBorder(0, 0, 3, 0));
1202                 buttonpanel.setOpaque(false);
1203                 JButton button = (JButton) buttonpanel.add(
1204                     new JButton(getString("AboutBox.ok_button_text"))
1205                 );
1206                 panel.add(buttonpanel, BorderLayout.SOUTH);
1207 
1208                 button.addActionListener(new OkAction(aboutBox));
1209             }
1210             aboutBox.pack();
1211             if (isApplet()) {
1212                 aboutBox.setLocationRelativeTo(getApplet());
1213             } else {
1214                 aboutBox.setLocationRelativeTo(getFrame());
1215             }
1216             aboutBox.show();
1217         }
1218     }
1219 
1220     class MultiScreenAction extends AbstractAction {
1221         static final int ALL_SCREENS = -1;
1222         int screen;
1223         protected MultiScreenAction(SwingSet2 swingset, int screen) {
1224             super("MultiScreenAction");
1225             this.screen = screen;
1226         }
1227 
1228         public void actionPerformed(ActionEvent e) {
1229             GraphicsDevice[] gds = GraphicsEnvironment.
1230                                    getLocalGraphicsEnvironment().
1231                                    getScreenDevices();
1232             if (screen == ALL_SCREENS) {
1233                 for (int i = 0; i < gds.length; i++) {
1234                     SwingSet2 swingset = new SwingSet2(null,
1235                                   gds[i].getDefaultConfiguration());
1236                     swingset.setDragEnabled(dragEnabled);
1237                 }
1238             }
1239             else {
1240                 SwingSet2 swingset = new SwingSet2(null,
1241                              gds[screen].getDefaultConfiguration());
1242                 swingset.setDragEnabled(dragEnabled);
1243             }
1244         }
1245     }
1246 
1247     // *******************************************************
1248     // **********************  Misc  *************************
1249     // *******************************************************
1250 
1251     class DemoLoadThread extends Thread {
1252         SwingSet2 swingset;
1253 
1254         DemoLoadThread(SwingSet2 swingset) {
1255             this.swingset = swingset;
1256         }
1257 
1258         public void run() {
1259             SwingUtilities.invokeLater(swingset::loadDemos);
1260         }
1261     }
1262 
1263     class AboutPanel extends JPanel {
1264         ImageIcon aboutimage = null;
1265         SwingSet2 swingset = null;
1266 
1267         public AboutPanel(SwingSet2 swingset) {
1268             this.swingset = swingset;
1269             aboutimage = swingset.createImageIcon("About.jpg", "AboutBox.accessible_description");
1270             setOpaque(false);
1271         }
1272 
1273         public void paint(Graphics g) {
1274             aboutimage.paintIcon(this, g, 0, 0);
1275             super.paint(g);
1276         }
1277 
1278         public Dimension getPreferredSize() {
1279             return new Dimension(aboutimage.getIconWidth(),
1280                                  aboutimage.getIconHeight());
1281         }
1282     }
1283 
1284 
1285     private class ChangeFontAction extends AbstractAction {
1286         private SwingSet2 swingset;
1287         private boolean plain;
1288 
1289         ChangeFontAction(SwingSet2 swingset, boolean plain) {
1290             super("FontMenu");
1291             this.swingset = swingset;
1292             this.plain = plain;
1293         }
1294 
1295         public void actionPerformed(ActionEvent e) {
1296             if (plain) {
1297                 UIManager.put("swing.boldMetal", Boolean.FALSE);
1298             }
1299             else {
1300                 UIManager.put("swing.boldMetal", Boolean.TRUE);
1301             }
1302             // Change the look and feel to force the settings to take effect.
1303             updateLookAndFeel();
1304         }
1305     }
1306 
1307     private static LookAndFeelData[] getInstalledLookAndFeelData() {
1308         return Arrays.stream(UIManager.getInstalledLookAndFeels())
1309                 .map(laf -> getLookAndFeelData(laf))
1310                 .toArray(LookAndFeelData[]::new);
1311     }
1312 
1313     private static LookAndFeelData getLookAndFeelData(
1314             UIManager.LookAndFeelInfo info) {
1315         switch (info.getName()) {
1316             case "Metal":
1317                 return new LookAndFeelData(info, "java");
1318             case "Nimbus":
1319                 return new LookAndFeelData(info, "nimbus");
1320             case "Windows":
1321                 return new LookAndFeelData(info, "windows");
1322             case "GTK+":
1323                 return new LookAndFeelData(info, "gtk");
1324             case "CDE/Motif":
1325                 return new LookAndFeelData(info, "motif");
1326             case "Mac OS X":
1327                 return new LookAndFeelData(info, "mac");
1328             default:
1329                 return new LookAndFeelData(info);
1330         }
1331     }
1332 
1333     private static class LookAndFeelData {
1334         String name;
1335         String className;
1336         String label;
1337         char mnemonic;
1338         String accDescription;
1339 
1340         public LookAndFeelData(UIManager.LookAndFeelInfo info) {
1341             this(info.getName(), info.getClassName(), info.getName(),
1342                  info.getName(), info.getName());
1343         }
1344 
1345         public LookAndFeelData(UIManager.LookAndFeelInfo info, String property) {
1346             this(info.getName(), info.getClassName(),
1347                     getString(String.format("LafMenu.%s_label", property)),
1348                     getString(String.format("LafMenu.%s_mnemonic", property)),
1349                     getString(String.format("LafMenu.%s_accessible_description",
1350                                     property)));
1351         }
1352 
1353         public LookAndFeelData(String name, String className, String label,
1354                                String mnemonic, String accDescription) {
1355             this.name = name;
1356             this.className = className;
1357             this.label = label;
1358             this.mnemonic = mnemonic.charAt(0);
1359             this.accDescription = accDescription;
1360         }
1361 
1362         @Override
1363         public String toString() {
1364             return className;
1365         }
1366     }
1367 }