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 
loadDemos()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 
SwingSet2(SwingSet2Applet applet)154     public SwingSet2(SwingSet2Applet applet) {
155         this(applet, null);
156     }
157 
158     /**
159      * SwingSet2 Constructor
160      */
SwingSet2(SwingSet2Applet applet, GraphicsConfiguration gc)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      */
main(final String[] args)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 
initializeDemo()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 {
stateChanged(ChangeEvent e)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      */
createMenus()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      */
createCheckBoxMenuItem(JMenu menu, String label, String mnemonic, String accessibleDescription, Action action)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      */
createButtonGroupMenuItem(JMenu menu, String label, String mnemonic, String accessibleDescription, Action action, ButtonGroup buttonGroup)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      */
createAudioMenuItem(JMenu menu, String label, String mnemonic, String accessibleDescription, Action action)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      */
createMenuItem(JMenu menu, String label, String mnemonic, String accessibleDescription, Action action)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      */
createThemesMenuItem(JMenu menu, String label, String mnemonic, String accessibleDescription, MetalTheme theme)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      */
createLafMenuItem(JMenu menu, LookAndFeelData lafData)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      */
createMultiscreenMenuItem(JMenu menu, int screen)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 
createPopupMenu()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      */
createPopupMenuItem(JPopupMenu menu, LookAndFeelData lafData)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      */
preloadFirstDemo()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      */
addDemo(DemoModule demo)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      */
setDemo(DemoModule demo)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      */
showSwingSet2()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 }
1368