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