1   /*
2    * Copyright (c) 2002 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.32 02/06/13
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.32 06/13/02
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 
108     // The current Look & Feel
109     private static String currentLookAndFeel = metal;
110 
111     // List of demos
112     private Vector demosVector = new Vector();
113 
114     // The preferred size of the demo
115     private static final int PREFERRED_WIDTH = 720;
116     private static final int PREFERRED_HEIGHT = 640;
117     
118     // Box spacers
119     private Dimension HGAP = new Dimension(1,5);
120     private Dimension VGAP = new Dimension(5,1);
121 
122     // Resource bundle for internationalized and accessible text
123     private ResourceBundle bundle = null;
124 
125     // A place to hold on to the visible demo
126     private DemoModule currentDemo = null;
127     private JPanel demoPanel = null;
128 
129     // About Box
130     private JDialog aboutBox = null;
131 
132     // Status Bar
133     private JTextField statusField = null;
134 
135     // Tool Bar
136     private ToggleButtonToolBar toolbar = null;
137     private ButtonGroup toolbarGroup = new ButtonGroup();
138 
139     // Menus
140     private JMenuBar menuBar = null;
141     private JMenu lafMenu = null;
142     private JMenu themesMenu = null;
143     private JMenu audioMenu = null;
144     private JMenu toolTipMenu = null;
145     private ButtonGroup lafMenuGroup = new ButtonGroup();
146     private ButtonGroup themesMenuGroup = new ButtonGroup();
147     private ButtonGroup audioMenuGroup = new ButtonGroup();
148     private ButtonGroup toolTipMenuGroup = new ButtonGroup();
149 
150     // Used only if swingset is an application 
151     private JFrame frame = null;
152     private JWindow splashScreen = null;
153 
154     // Used only if swingset is an applet 
155     private SwingSet2Applet applet = null;
156 
157     // To debug or not to debug, that is the question
158     private boolean DEBUG = true;
159     private int debugCounter = 0;
160 
161     // The tab pane that holds the demo
162     private JTabbedPane tabbedPane = null;
163 
164     private JEditorPane demoSrcPane = null;
165 
166     private JLabel splashLabel = null;
167 
168     // contentPane cache, saved from the applet or application frame
169     Container contentPane = null;
170 
171 
172     // number of swingsets - for multiscreen
173     // keep track of the number of SwingSets created - we only want to exit
174     // the program when the last one has been closed.
175     private static int numSSs = 0;
176     private static Vector swingSets = new Vector();
177 
178     public SwingSet2(SwingSet2Applet applet) {
179         this(applet, null);
180     }
181 
182     /**
183      * SwingSet2 Constructor
184      */
185     public SwingSet2(SwingSet2Applet applet, GraphicsConfiguration gc) {
186 
187     // Note that the applet may null if this is started as an application
188     this.applet = applet;
189 
190     // Create Frame here for app-mode so the splash screen can get the
191     // GraphicsConfiguration from it in createSplashScreen()
192     if (!isApplet()) {
193         frame = createFrame(gc);
194     }
195 
196     // setLayout(new BorderLayout());
197     setLayout(new BorderLayout());
198 
199     // set the preferred size of the demo
200     setPreferredSize(new Dimension(PREFERRED_WIDTH,PREFERRED_HEIGHT));
201 
202     // Create and throw the splash screen up. Since this will
203     // physically throw bits on the screen, we need to do this
204     // on the GUI thread using invokeLater.
205     createSplashScreen();
206 
207     // do the following on the gui thread
208     SwingUtilities.invokeLater(new Runnable() {
209         public void run() {
210         showSplashScreen();
211         }
212     });
213         
214     initializeDemo();
215     preloadFirstDemo();
216 
217     // Show the demo and take down the splash screen. Note that
218     // we again must do this on the GUI thread using invokeLater.
219     SwingUtilities.invokeLater(new Runnable() {
220         public void run() {
221         showSwingSet2();
222         hideSplash();
223         }
224     });
225 
226     // Start loading the rest of the demo in the background
227     DemoLoadThread demoLoader = new DemoLoadThread(this);
228     demoLoader.start();
229     }
230 
231 
232     /**
233      * SwingSet2 Main. Called only if we're an application, not an applet.
234      */
235     public static void main(String[] args) {
236     // Create SwingSet on the default monitor
237     SwingSet2 swingset = new SwingSet2(null, GraphicsEnvironment.
238                                              getLocalGraphicsEnvironment().
239                                              getDefaultScreenDevice().
240                                              getDefaultConfiguration());
241     }
242 
243     // *******************************************************
244     // *************** Demo Loading Methods ******************
245     // *******************************************************
246     
247     
248     
249     public void initializeDemo() {
250     JPanel top = new JPanel();
251     top.setLayout(new BorderLayout());
252     add(top, BorderLayout.NORTH);
253 
254     menuBar = createMenus();
255     top.add(menuBar, BorderLayout.NORTH);
256 
257     ToolBarPanel toolbarPanel = new ToolBarPanel();
258     toolbarPanel.setLayout(new BorderLayout());
259     toolbar = new ToggleButtonToolBar();
260     toolbarPanel.add(toolbar, BorderLayout.CENTER);
261     top.add(toolbarPanel, BorderLayout.SOUTH);
262     toolbarPanel.addContainerListener(toolbarPanel);
263 
264     tabbedPane = new JTabbedPane();
265     add(tabbedPane, BorderLayout.CENTER);
266     tabbedPane.getModel().addChangeListener(new TabListener());
267 
268     statusField = new JTextField("");
269     statusField.setEditable(false);
270     add(statusField, BorderLayout.SOUTH);
271     
272     demoPanel = new JPanel();
273     demoPanel.setLayout(new BorderLayout());
274     demoPanel.setBorder(new EtchedBorder());
275     tabbedPane.addTab("Hi There!", demoPanel);
276     
277     // Add html src code viewer 
278     demoSrcPane = new JEditorPane("text/html", getString("SourceCode.loading"));
279     demoSrcPane.setEditable(false);
280     
281     JScrollPane scroller = new JScrollPane();
282     scroller.getViewport().add(demoSrcPane);
283     
284     tabbedPane.addTab(
285         getString("TabbedPane.src_label"),
286         null,
287         scroller,
288         getString("TabbedPane.src_tooltip")
289     );
290     }
291 
292     DemoModule currentTabDemo = null;
293     class TabListener implements ChangeListener {
294     public void stateChanged(ChangeEvent e) {
295         SingleSelectionModel model = (SingleSelectionModel) e.getSource();
296         boolean srcSelected = model.getSelectedIndex() == 1;
297         if(currentTabDemo != currentDemo && demoSrcPane != null && srcSelected) {
298         demoSrcPane.setText(getString("SourceCode.loading"));
299         repaint();
300         }
301         if(currentTabDemo != currentDemo && srcSelected) {
302         currentTabDemo = currentDemo;
303         setSourceCode(currentDemo);
304         } 
305     }
306     }
307 
308 
309     /**
310      * Create menus
311      */
312     public JMenuBar createMenus() {
313     JMenuItem mi;
314     // ***** create the menubar ****
315     JMenuBar menuBar = new JMenuBar();
316     menuBar.getAccessibleContext().setAccessibleName(
317         getString("MenuBar.accessible_description"));
318 
319     // ***** create File menu 
320     JMenu fileMenu = (JMenu) menuBar.add(new JMenu(getString("FileMenu.file_label")));
321         fileMenu.setMnemonic(getMnemonic("FileMenu.file_mnemonic"));
322     fileMenu.getAccessibleContext().setAccessibleDescription(getString("FileMenu.accessible_description"));
323 
324     createMenuItem(fileMenu, "FileMenu.about_label", "FileMenu.about_mnemonic",
325                "FileMenu.about_accessible_description", new AboutAction(this));
326 
327         fileMenu.addSeparator();
328 
329     createMenuItem(fileMenu, "FileMenu.open_label", "FileMenu.open_mnemonic",
330                "FileMenu.open_accessible_description", null);
331 
332     createMenuItem(fileMenu, "FileMenu.save_label", "FileMenu.save_mnemonic",
333                "FileMenu.save_accessible_description", null);
334 
335     createMenuItem(fileMenu, "FileMenu.save_as_label", "FileMenu.save_as_mnemonic",
336                "FileMenu.save_as_accessible_description", null);
337 
338 
339     if(!isApplet()) {
340         fileMenu.addSeparator();
341         
342         createMenuItem(fileMenu, "FileMenu.exit_label", "FileMenu.exit_mnemonic",
343                "FileMenu.exit_accessible_description", new ExitAction(this)
344         );
345     }
346 
347         // Create these menu items for the first SwingSet only.
348         if (numSSs == 0) {
349     // ***** create laf switcher menu 
350     lafMenu = (JMenu) menuBar.add(new JMenu(getString("LafMenu.laf_label")));
351         lafMenu.setMnemonic(getMnemonic("LafMenu.laf_mnemonic"));
352     lafMenu.getAccessibleContext().setAccessibleDescription(
353         getString("LafMenu.laf_accessible_description"));
354 
355     mi = createLafMenuItem(lafMenu, "LafMenu.java_label", "LafMenu.java_mnemonic",
356                "LafMenu.java_accessible_description", metal);
357     mi.setSelected(true); // this is the default l&f
358 
359     createLafMenuItem(lafMenu, "LafMenu.mac_label", "LafMenu.mac_mnemonic",
360                "LafMenu.mac_accessible_description", mac);
361 
362     createLafMenuItem(lafMenu, "LafMenu.motif_label", "LafMenu.motif_mnemonic",
363                "LafMenu.motif_accessible_description", motif);
364 
365     createLafMenuItem(lafMenu, "LafMenu.windows_label", "LafMenu.windows_mnemonic",
366                "LafMenu.windows_accessible_description", windows);
367 
368     // ***** create themes menu 
369     themesMenu = (JMenu) menuBar.add(new JMenu(getString("ThemesMenu.themes_label")));
370         themesMenu.setMnemonic(getMnemonic("ThemesMenu.themes_mnemonic"));
371     themesMenu.getAccessibleContext().setAccessibleDescription(
372         getString("ThemesMenu.themes_accessible_description"));
373 
374     // ***** create the audio submenu under the theme menu
375     audioMenu = (JMenu) themesMenu.add(new JMenu(getString("AudioMenu.audio_label")));
376         audioMenu.setMnemonic(getMnemonic("AudioMenu.audio_mnemonic"));
377     audioMenu.getAccessibleContext().setAccessibleDescription(
378         getString("AudioMenu.audio_accessible_description"));
379 
380     createAudioMenuItem(audioMenu, "AudioMenu.on_label",
381                 "AudioMenu.on_mnemonic", 
382                 "AudioMenu.on_accessible_description",
383                 new OnAudioAction(this));
384 
385     mi = createAudioMenuItem(audioMenu, "AudioMenu.default_label",
386                  "AudioMenu.default_mnemonic", 
387                  "AudioMenu.default_accessible_description",
388                  new DefaultAudioAction(this));
389     mi.setSelected(true); // This is the default feedback setting
390 
391     createAudioMenuItem(audioMenu, "AudioMenu.off_label",
392                 "AudioMenu.off_mnemonic", 
393                 "AudioMenu.off_accessible_description",
394                 new OffAudioAction(this));
395 
396     // *** now back to adding color/font themes to the theme menu
397     mi = createThemesMenuItem(themesMenu, "ThemesMenu.default_label", "ThemesMenu.default_mnemonic",
398                "ThemesMenu.default_accessible_description", new DefaultMetalTheme());
399     mi.setSelected(true); // This is the default theme
400     
401     createThemesMenuItem(themesMenu, "ThemesMenu.aqua_label", "ThemesMenu.aqua_mnemonic",
402                "ThemesMenu.aqua_accessible_description", new AquaTheme());
403 
404     createThemesMenuItem(themesMenu, "ThemesMenu.charcoal_label", "ThemesMenu.charcoal_mnemonic",
405                "ThemesMenu.charcoal_accessible_description", new CharcoalTheme());
406 
407     createThemesMenuItem(themesMenu, "ThemesMenu.contrast_label", "ThemesMenu.contrast_mnemonic",
408                "ThemesMenu.contrast_accessible_description", new ContrastTheme());
409 
410     createThemesMenuItem(themesMenu, "ThemesMenu.emerald_label", "ThemesMenu.emerald_mnemonic",
411                "ThemesMenu.emerald_accessible_description", new EmeraldTheme());
412 
413     createThemesMenuItem(themesMenu, "ThemesMenu.ruby_label", "ThemesMenu.ruby_mnemonic",
414                "ThemesMenu.ruby_accessible_description", new RubyTheme());
415 
416     // ***** create the tooltip menu.
417     toolTipMenu = (JMenu) menuBar.add(new JMenu(
418                 getString("ToolTipMenu.tooltip_label")));
419         toolTipMenu.setMnemonic(getMnemonic("ToolTipMenu.tooltip_mnemonic"));
420     toolTipMenu.getAccessibleContext().setAccessibleDescription(
421         getString("ToolTipMenu.tooltip_accessible_description"));
422 
423         // ***** create tool tip submenu items.
424         mi = createToolTipMenuItem(toolTipMenu, "ToolTipMenu.on_label",
425                 "ToolTipMenu.on_mnemonic",
426                 "ToolTipMenu.on_accessible_description",
427                 new ToolTipAction(this, true));
428         mi.setSelected(true);
429 
430         createToolTipMenuItem(toolTipMenu, "ToolTipMenu.off_label",
431                 "ToolTipMenu.off_mnemonic",
432                 "ToolTipMenu.off_accessible_description",
433                 new ToolTipAction(this, false));
434         }
435 
436 
437     // ***** create the multiscreen menu, if we have multiple screens
438     if (!isApplet()) {
439         GraphicsDevice[] screens = GraphicsEnvironment.
440                                     getLocalGraphicsEnvironment().
441                                     getScreenDevices();
442         if (screens.length > 1) {
443 
444             JMenu multiScreenMenu = (JMenu) menuBar.add(new JMenu(
445                                      getString("MultiMenu.multi_label")));
446 
447             multiScreenMenu.setMnemonic(getMnemonic("MultiMenu.multi_mnemonic"));    
448             multiScreenMenu.getAccessibleContext().setAccessibleDescription(
449              getString("MultiMenu.multi_accessible_description"));
450 
451             createMultiscreenMenuItem(multiScreenMenu, MultiScreenAction.ALL_SCREENS);
452             for (int i = 0; i < screens.length; i++) {
453                 createMultiscreenMenuItem(multiScreenMenu, i);
454             }
455         }
456     }
457 
458     return menuBar;
459     }
460 
461     /**
462      * Create the tool tip submenu
463      */
464     public JMenuItem createToolTipMenuItem(JMenu menu, String label,
465                                            String mnemonic,
466                                            String accessibleDescription,
467                                            Action action) {
468         JRadioButtonMenuItem mi = (JRadioButtonMenuItem)menu.add(
469                 new JRadioButtonMenuItem(getString(label)));
470         toolTipMenuGroup.add(mi);
471         mi.setMnemonic(getMnemonic(mnemonic));
472         mi.getAccessibleContext().setAccessibleDescription(getString(
473                 accessibleDescription));
474         mi.addActionListener(action);
475 
476         return mi;
477     }
478 
479     /**
480      * Create the theme's audio submenu
481      */
482     public JMenuItem createAudioMenuItem(JMenu menu, String label,
483                      String mnemonic,
484                      String accessibleDescription,
485                      Action action) {
486         JRadioButtonMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(getString(label)));
487     audioMenuGroup.add(mi);
488     mi.setMnemonic(getMnemonic(mnemonic));
489     mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
490     mi.addActionListener(action);
491 
492     return mi;
493     }
494 
495     /**
496      * Creates a generic menu item
497      */
498     public JMenuItem createMenuItem(JMenu menu, String label, String mnemonic,
499                    String accessibleDescription, Action action) {
500         JMenuItem mi = (JMenuItem) menu.add(new JMenuItem(getString(label)));
501     mi.setMnemonic(getMnemonic(mnemonic));
502     mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
503     mi.addActionListener(action);
504     if(action == null) {
505         mi.setEnabled(false);
506     }
507     return mi;
508     }
509 
510     /**
511      * Creates a JRadioButtonMenuItem for the Themes menu
512      */
513     public JMenuItem createThemesMenuItem(JMenu menu, String label, String mnemonic,
514                    String accessibleDescription, DefaultMetalTheme theme) {
515         JRadioButtonMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(getString(label)));
516     themesMenuGroup.add(mi);
517     mi.setMnemonic(getMnemonic(mnemonic));
518     mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
519     mi.addActionListener(new ChangeThemeAction(this, theme));
520 
521     return mi;
522     }
523 
524     /**
525      * Creates a JRadioButtonMenuItem for the Look and Feel menu
526      */
527     public JMenuItem createLafMenuItem(JMenu menu, String label, String mnemonic,
528                    String accessibleDescription, String laf) {
529         JMenuItem mi = (JRadioButtonMenuItem) menu.add(new JRadioButtonMenuItem(getString(label)));
530     lafMenuGroup.add(mi);
531     mi.setMnemonic(getMnemonic(mnemonic));
532     mi.getAccessibleContext().setAccessibleDescription(getString(accessibleDescription));
533     mi.addActionListener(new ChangeLookAndFeelAction(this, laf));
534 
535     mi.setEnabled(isAvailableLookAndFeel(laf));
536 
537     return mi;
538     }
539 
540     /**
541      * Creates a multi-screen menu item
542      */
543     public JMenuItem createMultiscreenMenuItem(JMenu menu, int screen) {
544         JMenuItem mi = null;
545         if (screen == MultiScreenAction.ALL_SCREENS) {
546             mi = (JMenuItem) menu.add(new JMenuItem(getString("MultiMenu.all_label")));
547             mi.setMnemonic(getMnemonic("MultiMenu.all_mnemonic"));
548             mi.getAccessibleContext().setAccessibleDescription(getString(
549                                                                  "MultiMenu.all_accessible_description"));
550         }
551         else {
552             mi = (JMenuItem) menu.add(new JMenuItem(getString("MultiMenu.single_label") + " " +
553                                                                                                  screen));
554             mi.setMnemonic(KeyEvent.VK_0 + screen);
555             mi.getAccessibleContext().setAccessibleDescription(getString(
556                                                "MultiMenu.single_accessible_description") + " " + screen);
557                                                                                             
558         }
559         mi.addActionListener(new MultiScreenAction(this, screen));
560         return mi;
561     }
562 
563     /**
564      * Load the first demo. This is done separately from the remaining demos
565      * so that we can get SwingSet2 up and available to the user quickly.
566      */
567     public void preloadFirstDemo() {
568     DemoModule demo = addDemo(new InternalFrameDemo(this));
569     setDemo(demo);
570     }
571 
572 
573     /**
574      * Add a demo to the toolbar
575      */
576     public DemoModule addDemo(DemoModule demo) {
577     demosVector.addElement(demo);
578     // do the following on the gui thread
579     SwingUtilities.invokeLater(new SwingSetRunnable(this, demo) {
580         public void run() {
581         SwitchToDemoAction action = new SwitchToDemoAction(swingset, (DemoModule) obj);
582         JToggleButton tb = swingset.getToolBar().addToggleButton(action);
583         swingset.getToolBarGroup().add(tb);
584         if(swingset.getToolBarGroup().getSelection() == null) {
585             tb.setSelected(true);
586         }
587         tb.setText(null);
588         tb.setToolTipText(((DemoModule)obj).getToolTip());
589 
590         if(demos[demos.length-1].equals(obj.getClass().getName())) {
591             setStatus("");
592         } 
593           
594         }
595     });
596     return demo;
597     }
598 
599 
600     /**
601      * Sets the current demo
602      */
603     public void setDemo(DemoModule demo) {
604     currentDemo = demo;
605 
606     // Ensure panel's UI is current before making visible
607     JComponent currentDemoPanel = demo.getDemoPanel();
608     SwingUtilities.updateComponentTreeUI(currentDemoPanel);
609 
610     demoPanel.removeAll();
611     demoPanel.add(currentDemoPanel, BorderLayout.CENTER);
612 
613     tabbedPane.setSelectedIndex(0);
614     tabbedPane.setTitleAt(0, demo.getName());
615     tabbedPane.setToolTipTextAt(0, demo.getToolTip());
616     }
617 
618 
619     /**
620      * Bring up the SwingSet2 demo by showing the frame (only
621      * applicable if coming up as an application, not an applet);
622      */
623     public void showSwingSet2() {
624     if(!isApplet() && getFrame() != null) {
625         // put swingset in a frame and show it
626         JFrame f = getFrame();
627         f.setTitle(getString("Frame.title"));
628         f.getContentPane().add(this, BorderLayout.CENTER);
629         f.pack();
630 
631         Rectangle screenRect = f.getGraphicsConfiguration().getBounds();
632             Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(
633                     f.getGraphicsConfiguration());
634 
635             // Make sure we don't place the demo off the screen.
636             int centerWidth = screenRect.width < f.getSize().width ?
637                     screenRect.x :
638                     screenRect.x + screenRect.width/2 - f.getSize().width/2;
639             int centerHeight = screenRect.height < f.getSize().height ?
640                     screenRect.y :
641                     screenRect.y + screenRect.height/2 - f.getSize().height/2;
642 
643             centerHeight = centerHeight < screenInsets.top ?
644                     screenInsets.top : centerHeight;
645 
646             f.setLocation(centerWidth, centerHeight);
647         f.show();
648             numSSs++;
649             swingSets.add(this);
650     } 
651     }
652 
653     /**
654      * Show the spash screen while the rest of the demo loads
655      */
656     public void createSplashScreen() {
657     splashLabel = new JLabel(createImageIcon("Splash.jpg", "Splash.accessible_description"));
658     
659     if(!isApplet()) {
660         splashScreen = new JWindow(getFrame());
661         splashScreen.getContentPane().add(splashLabel);
662         splashScreen.pack();
663         Rectangle screenRect = getFrame().getGraphicsConfiguration().getBounds();
664         splashScreen.setLocation(
665          screenRect.x + screenRect.width/2 - splashScreen.getSize().width/2,
666          screenRect.y + screenRect.height/2 - splashScreen.getSize().height/2);
667     } 
668     }
669 
670     public void showSplashScreen() {
671     if(!isApplet()) {
672         splashScreen.show();
673     } else {
674         add(splashLabel, BorderLayout.CENTER);
675         validate();
676         repaint();
677     }
678     }
679 
680     /**
681      * pop down the spash screen
682      */
683     public void hideSplash() {
684     if(!isApplet()) {
685         splashScreen.setVisible(false);
686         splashScreen = null;
687         splashLabel = null;
688     }
689     }
690 
691     // *******************************************************
692     // ****************** Utility Methods ********************
693     // *******************************************************
694 
695     /**
696      * Loads a demo from a classname
697      */
698     void loadDemo(String classname) {
699     setStatus(getString("Status.loading") + getString(classname + ".name"));
700     DemoModule demo = null;
701     try {
702         Class demoClass = Class.forName(classname);
703         Constructor demoConstructor = demoClass.getConstructor(new Class[]{SwingSet2.class});
704         demo = (DemoModule) demoConstructor.newInstance(new Object[]{this});
705         addDemo(demo);
706     } catch (Exception e) {
707         System.out.println("Error occurred loading demo: " + classname);
708     }
709     }
710     
711     /**
712      * A utility function that layers on top of the LookAndFeel's
713      * isSupportedLookAndFeel() method. Returns true if the LookAndFeel
714      * is supported. Returns false if the LookAndFeel is not supported
715      * and/or if there is any kind of error checking if the LookAndFeel
716      * is supported.
717      *
718      * The L&F menu will use this method to detemine whether the various
719      * L&F options should be active or inactive.
720      *
721      */
722      protected boolean isAvailableLookAndFeel(String laf) {
723          try { 
724              Class lnfClass = Class.forName(laf);
725              LookAndFeel newLAF = (LookAndFeel)(lnfClass.newInstance());
726              return newLAF.isSupportedLookAndFeel();
727          } catch(Exception e) { // If ANYTHING weird happens, return false
728              return false;
729          }
730      }
731 
732 
733     /**
734      * Determines if this is an applet or application
735      */
736     public boolean isApplet() {
737     return (applet != null);
738     }
739 
740     /**
741      * Returns the applet instance
742      */
743     public SwingSet2Applet getApplet() {
744     return applet;
745     }
746 
747 
748     /**
749      * Returns the frame instance
750      */
751     public JFrame getFrame() {
752     return frame;
753     }
754 
755     /**
756      * Returns the menubar
757      */
758     public JMenuBar getMenuBar() {
759     return menuBar;
760     }
761 
762     /**
763      * Returns the toolbar
764      */
765     public ToggleButtonToolBar getToolBar() {
766     return toolbar;
767     }
768 
769     /**
770      * Returns the toolbar button group
771      */
772     public ButtonGroup getToolBarGroup() {
773     return toolbarGroup;
774     }
775 
776     /**
777      * Returns the content pane wether we're in an applet
778      * or application
779      */
780     public Container getContentPane() {
781     if(contentPane == null) {
782         if(getFrame() != null) {
783         contentPane = getFrame().getContentPane();
784         } else if (getApplet() != null) {
785         contentPane = getApplet().getContentPane();
786         }
787     }
788     return contentPane;
789     }
790 
791     /**
792      * Create a frame for SwingSet2 to reside in if brought up
793      * as an application.
794      */
795     public static JFrame createFrame(GraphicsConfiguration gc) {
796     JFrame frame = new JFrame(gc);
797         if (numSSs == 0) {
798             frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
799         } else {
800         WindowListener l = new WindowAdapter() {
801             public void windowClosing(WindowEvent e) {
802                     numSSs--;
803                     swingSets.remove(this);
804             }
805         };
806         frame.addWindowListener(l);
807         }
808     return frame;
809     }
810 
811 
812     /**
813      * Set the status 
814      */
815     public void setStatus(String s) {
816     // do the following on the gui thread
817     SwingUtilities.invokeLater(new SwingSetRunnable(this, s) {
818         public void run() {
819         swingset.statusField.setText((String) obj);
820         }
821     });
822     }
823 
824 
825     /**
826      * This method returns a string from the demo's resource bundle.
827      */
828     public String getString(String key) {
829     String value = null;
830     try {
831         value = getResourceBundle().getString(key);
832     } catch (MissingResourceException e) {
833         System.out.println("java.util.MissingResourceException: Couldn't find value for: " + key);
834     }
835     if(value == null) {
836         value = "Could not find resource: " + key + "  ";
837     }
838     return value;
839     }
840 
841     /**
842      * Returns the resource bundle associated with this demo. Used
843      * to get accessable and internationalized strings.
844      */
845     public ResourceBundle getResourceBundle() {
846     if(bundle == null) {
847         bundle = ResourceBundle.getBundle("resources.swingset");
848     }
849     return bundle;
850     }
851 
852     /**
853      * Returns a mnemonic from the resource bundle. Typically used as
854      * keyboard shortcuts in menu items.
855      */
856     public char getMnemonic(String key) {
857     return (getString(key)).charAt(0);
858     }
859 
860     /**
861      * Creates an icon from an image contained in the "images" directory.
862      */
863     public ImageIcon createImageIcon(String filename, String description) {
864     String path = "/resources/images/" + filename;
865     return new ImageIcon(getClass().getResource(path)); 
866     }
867 
868     /**
869      * If DEBUG is defined, prints debug information out to std ouput.
870      */
871     public void debug(String s) {
872     if(DEBUG) {
873         System.out.println((debugCounter++) + ": " + s);
874     }
875     }
876 
877     /**
878      * Stores the current L&F, and calls updateLookAndFeel, below
879      */
880     public void setLookAndFeel(String laf) {
881     if(currentLookAndFeel != laf) {
882         currentLookAndFeel = laf;
883         themesMenu.setEnabled(laf == metal);
884         updateLookAndFeel();
885     }
886     }
887 
888     /**
889      * Sets the current L&F on each demo module
890      */
891     public void updateLookAndFeel() {
892     try {
893         UIManager.setLookAndFeel(currentLookAndFeel);
894             for (Iterator itr = swingSets.iterator(); itr.hasNext(); ) {
895                 SwingSet2 ss = (SwingSet2)itr.next();
896             SwingUtilities.updateComponentTreeUI(ss);
897             }
898             // update LAF for the toplevel frame, too
899             if (!isApplet()) {
900                 SwingUtilities.updateComponentTreeUI(getFrame());
901             } else {
902                 SwingUtilities.updateComponentTreeUI(getApplet());
903             }
904 
905     } catch (Exception ex) {
906         System.out.println("Failed loading L&F: " + currentLookAndFeel);
907         System.out.println(ex);
908     }
909 
910     // lazily update update the UI's for the remaining demos
911     for (int i = 0; i < demosVector.size(); i++) {
912         DemoModule demo = (DemoModule) demosVector.elementAt(i);
913         if(currentDemo != demo) {
914         // do the following on the gui thread
915         SwingUtilities.invokeLater(new SwingSetRunnable(this, demo) {
916             public void run() {
917             SwingUtilities.updateComponentTreeUI(((DemoModule)obj).getDemoPanel());
918             }
919         });
920         }
921     }
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    String laf;
1056        protected ChangeLookAndFeelAction(SwingSet2 swingset, String laf) {
1057            super("ChangeTheme");
1058        this.swingset = swingset;
1059        this.laf = laf;
1060        }
1061
1062        public void actionPerformed(ActionEvent e) {
1063        swingset.setLookAndFeel(laf);
1064    }
1065    }
1066
1067    // Turns on all possible auditory feedback
1068    class OnAudioAction extends AbstractAction {
1069    SwingSet2 swingset;
1070        protected OnAudioAction(SwingSet2 swingset) {
1071            super("Audio On");
1072        this.swingset = swingset;
1073        }
1074        public void actionPerformed(ActionEvent e) {
1075        UIManager.put("AuditoryCues.playList",
1076              UIManager.get("AuditoryCues.allAuditoryCues"));
1077        swingset.updateLookAndFeel();
1078    }
1079    }
1080
1081    // Turns on the default amount of auditory feedback
1082    class DefaultAudioAction extends AbstractAction {
1083    SwingSet2 swingset;
1084        protected DefaultAudioAction(SwingSet2 swingset) {
1085            super("Audio Default");
1086        this.swingset = swingset;
1087        }
1088        public void actionPerformed(ActionEvent e) {
1089        UIManager.put("AuditoryCues.playList",
1090              UIManager.get("AuditoryCues.defaultCueList"));
1091        swingset.updateLookAndFeel();
1092    }
1093    }
1094
1095    // Turns off all possible auditory feedback
1096    class OffAudioAction extends AbstractAction {
1097    SwingSet2 swingset;
1098        protected OffAudioAction(SwingSet2 swingset) {
1099            super("Audio Off");
1100        this.swingset = swingset;
1101        }
1102        public void actionPerformed(ActionEvent e) {
1103        UIManager.put("AuditoryCues.playList",
1104              UIManager.get("AuditoryCues.noAuditoryCues"));
1105        swingset.updateLookAndFeel();
1106    }
1107    }
1108
1109    // Turns on or off the tool tips for the demo.
1110    class ToolTipAction extends AbstractAction {
1111        SwingSet2 swingset;
1112        boolean status;
1113        protected ToolTipAction(SwingSet2 swingset, boolean status) {
1114            super("ToolTip Control");
1115            this.swingset = swingset;
1116            this.status = status;
1117        }
1118
1119        public void actionPerformed(ActionEvent e) {
1120            ToolTipManager.sharedInstance().setEnabled(status);
1121        }
1122    }
1123
1124    class ChangeThemeAction extends AbstractAction {
1125    SwingSet2 swingset;
1126    DefaultMetalTheme theme;
1127        protected ChangeThemeAction(SwingSet2 swingset, DefaultMetalTheme theme) {
1128            super("ChangeTheme");
1129        this.swingset = swingset;
1130        this.theme = theme;
1131        }
1132
1133        public void actionPerformed(ActionEvent e) {
1134        MetalLookAndFeel.setCurrentTheme(theme);
1135        swingset.updateLookAndFeel();
1136    }
1137    }
1138
1139    class ExitAction extends AbstractAction {
1140    SwingSet2 swingset;
1141        protected ExitAction(SwingSet2 swingset) {
1142            super("ExitAction");
1143        this.swingset = swingset;
1144        }
1145
1146        public void actionPerformed(ActionEvent e) {
1147        System.exit(0);
1148        }
1149    }
1150
1151    class AboutAction extends AbstractAction {
1152    SwingSet2 swingset;
1153        protected AboutAction(SwingSet2 swingset) {
1154            super("AboutAction");
1155        this.swingset = swingset;
1156        }
1157    
1158        public void actionPerformed(ActionEvent e) {
1159        if(aboutBox == null) {
1160        // JPanel panel = new JPanel(new BorderLayout());
1161        JPanel panel = new AboutPanel(swingset);
1162        panel.setLayout(new BorderLayout());
1163
1164        aboutBox = new JDialog(swingset.getFrame(), getString("AboutBox.title"), false);
1165        aboutBox.getContentPane().add(panel, BorderLayout.CENTER);
1166
1167        // JButton button = new JButton(getString("AboutBox.ok_button_text"));
1168        JPanel buttonpanel = new JPanel();
1169        buttonpanel.setOpaque(false);
1170        JButton button = (JButton) buttonpanel.add(
1171            new JButton(getString("AboutBox.ok_button_text"))
1172        );
1173        panel.add(buttonpanel, BorderLayout.SOUTH);
1174
1175        button.addActionListener(new OkAction(aboutBox));
1176        }
1177        aboutBox.pack();
1178        Point p = swingset.getLocationOnScreen();
1179        aboutBox.setLocation(p.x + 10, p.y +10);
1180        aboutBox.show();
1181    }
1182    }
1183
1184    class MultiScreenAction extends AbstractAction {
1185        static final int ALL_SCREENS = -1;
1186        int screen;
1187        protected MultiScreenAction(SwingSet2 swingset, int screen) {
1188            super("MultiScreenAction");
1189            this.screen = screen;
1190        }
1191
1192        public void actionPerformed(ActionEvent e) {
1193            GraphicsDevice[] gds = GraphicsEnvironment.
1194                                   getLocalGraphicsEnvironment().
1195                                   getScreenDevices();
1196            if (screen == ALL_SCREENS) {
1197                for (int i = 0; i < gds.length; i++) {
1198                    SwingSet2 swingset = new SwingSet2(null,
1199                                  gds[i].getDefaultConfiguration());
1200                }
1201            }
1202            else {
1203                SwingSet2 swingset = new SwingSet2(null,
1204                             gds[screen].getDefaultConfiguration());
1205            }
1206        }
1207    }
1208
1209    // *******************************************************
1210    // **********************  Misc  *************************
1211    // *******************************************************
1212
1213    class DemoLoadThread extends Thread {
1214    SwingSet2 swingset;
1215    
1216    public DemoLoadThread(SwingSet2 swingset) {
1217        this.swingset = swingset;
1218    }
1219
1220    public void run() {
1221        swingset.loadDemos();
1222    }
1223    }
1224
1225    class AboutPanel extends JPanel {
1226    ImageIcon aboutimage = null;
1227    SwingSet2 swingset = null;
1228
1229    public AboutPanel(SwingSet2 swingset) {
1230        this.swingset = swingset;
1231        aboutimage = swingset.createImageIcon("About.jpg", "AboutBox.accessible_description");
1232        setOpaque(false);
1233    }
1234
1235    public void paint(Graphics g) {
1236        aboutimage.paintIcon(this, g, 0, 0);
1237        super.paint(g);
1238    }
1239
1240    public Dimension getPreferredSize() {
1241        return new Dimension(aboutimage.getIconWidth(),
1242                 aboutimage.getIconHeight());
1243    }
1244    }
1245
1246}
1247
1248