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