/* * Licensed Materials - Property of Perforce Software, Inc. * © Copyright Perforce Software, Inc. 2014, 2021 * © Copyright IBM Corp. 2009, 2014 * © Copyright ILOG 1996, 2009 * All Rights Reserved. * * Note to U.S. Government Users Restricted Rights: * The Software and Documentation were developed at private expense and * are "Commercial Items" as that term is defined at 48 CFR 2.101, * consisting of "Commercial Computer Software" and * "Commercial Computer Software Documentation", as such terms are * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4, * as applicable. */ package shared; import ilog.views.gantt.action.IlvAction; import ilog.views.util.IlvImageUtil; import ilog.views.util.java.Version; import ilog.views.util.swing.IlvSwingUtil; import ilog.views.util.swing.color.IlvJColorChooser; import java.awt.*; import java.awt.event.*; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.net.URL; import java.util.*; import java.util.List; import javax.swing.*; import javax.swing.border.BevelBorder; import javax.swing.event.MenuDragMouseEvent; import javax.swing.event.MenuDragMouseListener; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolTipUI; import javax.swing.text.View; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import shared.help.HelpSystem; import shared.help.NoHelpSystem; /** * This is the abstract base class for all of the Gantt module demos. It * contains much of the common code for handling the menus, the status bar, * and so on. */ public abstract class AbstractExample extends JRootPane { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractExample.class); // ========================================= // Instance Variables // ========================================= /** * The adapter that collects the status text of each menu and displays it in * the status bar. */ private MenuInfo menuStatusAdapter; /** * The status bar used for showing information when menu items are selected. */ private JLabel status; /** * The toolbar. */ private JToolBar toolbar; /** * The example's top-level ancestor. This is the first ancestor of the example * that is a Window. */ private JFrame rootAncestor; /** * The example's explicit locale. This is a duplication of the private * <code>locale</code> field of the <code>Component</code> superclass. It is * repeated here so that we can test whether the locale has been explicity * set or is being inherited from its parent container. */ private Locale locale = null; /** * A blank icon. */ private Icon blankIcon = null; /** * Indicates whether we have attempted to load the blank icon. */ private boolean blankIconInit = false; /** * Indicates whether this example has permission to access the * local file system. */ private Boolean localFileAccessAllowed; /** * The help system for the example. */ private HelpSystem helpSystem; /** * Help actions. */ protected IlvAction helpAction; protected IlvAction contextHelpAction; // ========================================= // Class Constants // ========================================= /** * The client-property lookup key for status text of each menu item. */ private static final String STATUS_TEXT_KEY = "StatusText"; /** * The client-property lookup key for whether a <code>JMenu</code> has any * menu item icons. */ private static final String MENU_ITEM_ICONS_KEY = "MenuItemIcons"; /** * The blank icon filename. */ private static final String BLANK_ICON = "images/blank.gif"; // ========================================= // Instance Construction and Initialization // ========================================= /** * Creates a new <code>AbstractExample</code>. */ public AbstractExample() { // This will prevent the "SystemEventQueue" access message from appearing // in the Java console when this example is in a browser. getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE); menuStatusAdapter = new MenuInfo(); } /** * Initializes the example's user interface in the specified container. * * @param container The container that the example is running in. This will * be the <code>JFrame</code> of the application. */ public void init(Container container) { // If the locale has not been explicitly set, use the locale of the // container. if (locale == null) { setLocale(container.getLocale()); } rootAncestor=(JFrame) SwingUtilities.getWindowAncestor(container); // Load custom L&Fs using the app's classloader. This works around JavaSoft // Bug #4155617, which prevents custom L&Fs from being loaded by the plugin. UIManager.put("ClassLoader", getClass().getClassLoader()); // Disable the Metal tooltip L&F because, as of JDK 1.2.2, it displays // accelerator bindings incorrectly. See JavaSoft Bug #4306876. UIManager.put("ToolTipUI", "shared.AbstractExample$ToolTipUI"); // Initialize the Help System initHelpSystem(); } /** * This method is invoked after the example's user interface has been displayed * for the first time. You can override this method to perform customizations that * require a correctly positioned and laid out user interface, such as zooming to * fit. */ public void postInit() { } /** * Returns the title of the example. * * @return The title of the example. */ public abstract String getTitle(); /** * Sets the locale of the example. This method is overridden to store a * locally accessible copy of the locale. * * @param locale The locale. */ Override public void setLocale(Locale locale) { this.locale = locale; super.setLocale(locale); } /** * Sets the language-sensitive orientation of the example. * @param o The orientation. */ Override public void setComponentOrientation(ComponentOrientation o) { IlvSwingUtil.updateComponentTreeOrientation(rootAncestor, o); } // ========================================= // Application Permissions // ========================================= /** * Returns <code>true</code> if this example has permission to exit the * Java VM. * * @return Whether the example has permission to exit the JVM. */ protected boolean isExitAllowed() { SecurityManager security = System.getSecurityManager(); if (security == null) { return true; } try { security.checkExit(0); } catch (SecurityException e) { return false; } return true; } /** * Returns <code>true</code> if this example should offer printing services. */ protected boolean isPrintingConfigured() { return true; } /** * Returns <code>true</code> if this example has permission to print. * * @return Whether the example has permission to print. */ protected boolean isPrintingAllowed() { SecurityManager security = System.getSecurityManager(); if (security == null) { return true; } try { security.checkPrintJobAccess(); } catch (SecurityException e) { return false; } return true; } /** * Returns <code>true</code> if this example has permission to access the * local file system. Typically, this will be <code>true</code> if the example * is running as an application. * * @return Whether the example has permission to access the local file system. */ protected boolean isLocalFileAccessAllowed() { if (localFileAccessAllowed == null) { localFileAccessAllowed = Boolean.TRUE; // If there is no security manager, then we are probably running as an // application and everything is allowed. Otherwise, we check that we can // read the user's current directory. SecurityManager security = System.getSecurityManager(); if (security != null) { try { security.checkPropertyAccess("user.dir"); String dir = System.getProperty("user.dir"); security.checkRead(dir); } catch (SecurityException e) { localFileAccessAllowed = Boolean.FALSE; } } } return localFileAccessAllowed; } // ========================================= // Accessing Resources // ========================================= /** * Returns the fully qualified URL of a resource file that is specified relative to the * working directory of the example. Note that this is different than calling * <code>Class.getResource()</code>, which performs resource lookup relative to the * example's classpath. * * @param relativePath The path of the resource file, relative to the working directory * of the example. * @return The resource URL. * @throws IOException if the path cannot be resolved to a valid and existing URL. * */ public URL getResourceURL(String relativePath) throws IOException { relativePath = relativePath.replace('\\', '/'); URL url = null; // In an application context, we try to find an external file relative to the // current working directory. If an external file does not exist, then the file // may be bundled into the jar with the classes. In this case, we prepend a '/' // to relativePath so that we search relative to the classloader's root and not // relative to the packaging of the current class. File file = new File(relativePath); // If the file exists in the external file system, we return its corresponding URL. if (file.exists()) { url = file.toURI().toURL(); } // Otherwise, we search for the file relative to the classloader's root. This will // find the file if it is packaged into a jar with the classes. else { // Prepend a '/' so that we search relative to the classloader's root and not // relative to the packaging of the current class. if (relativePath.charAt(0) != '/') { relativePath = '/' + relativePath; } url = getClass().getResource(relativePath); } // Verify that we have a valid URL by trying to open its associated stream. if (url == null) { throw new FileNotFoundException(relativePath); } InputStream stream = url.openStream(); stream.close(); return url; } // ========================================= // Status Bar // ========================================= /** * Sets the status text of the specified component. * * @param component The component. * @param text The status text. */ protected void setStatusText(JComponent component, String text) { component.putClientProperty(STATUS_TEXT_KEY, text); if (component instanceof JMenuItem) { JMenuItem menuItem = (JMenuItem) component; menuItem.addMenuDragMouseListener(menuStatusAdapter); if (!(menuItem instanceof JMenu)) { menuItem.addMouseMotionListener(menuStatusAdapter); } } if (component instanceof JMenu) { ((JMenu) component).addMenuListener(menuStatusAdapter); } } /** * Returns the status text of the specified component. * * @param component The component. * @return The status text. */ protected String getStatusText(JComponent component) { return (String) component.getClientProperty(STATUS_TEXT_KEY); } /** * Creates the status bar component. * * @return The status bar. */ protected JLabel createStatusBar() { status = new JLabel(" "); status.setBorder(new BevelBorder(BevelBorder.LOWERED)); return status; } /** * Returns the status bar component. * * @return The status bar. */ protected JLabel getStatusBar() { return status; } // ========================================= // ToolBar // ========================================= /** * Creates the toolbar component. * * @return The toolbar. */ protected JToolBar createToolBar() { toolbar = new JToolBar(); toolbar.setFloatable(false); populateToolBar(toolbar); return toolbar; } /** * Populates the specified toolbar. This default implementation does nothing. * Subclasses should override this method as needed. * * @param toolbar The toolbar. */ protected void populateToolBar(JToolBar toolbar) { } /** * Returns the toolbar component. * * @return The toolbar. */ protected JToolBar getToolBar() { return toolbar; } /** * Adds the specified action to a toolbar and returns the created * <code>JButton</code>. * * @param toolbar The toolbar. * @param action The action. * @return The button. */ protected JButton addAction(JToolBar toolbar, IlvAction action) { // Create the button from the action. This configures the button text, icon, // tooltip, and mnemonic. JButton button = new JButton(action); // Only use text on buttons if there is no icon. if (button.getIcon() != null) { button.setText(null); } // Register the accelerator as a window-wide shortcut. KeyStroke accelerator = action.getAccelerator(); if (accelerator != null) { button.registerKeyboardAction(action, accelerator, JButton.WHEN_IN_FOCUSED_WINDOW); } // Add the accerator key to the end of the tooltip. String shortDescription = action.getShortDescription(); if (shortDescription != null) { if (accelerator != null) { shortDescription += ToolTipUI.TIP_DELIMITER + action.getAcceleratorText(); } button.setToolTipText(shortDescription); } // Add the button to the toolbar. toolbar.add(button); return button; } // ========================================= // Menus // ========================================= /** * Sets the menu bar for the top-level ancestor of the sample (either the * containing <code>JFrame</code> ). */ Override public void setJMenuBar(JMenuBar menuBar) { ((JFrame)rootAncestor).setJMenuBar(menuBar); } /** * Returns the blank icon that can be used to left-align menu items that do * not have an icon of their own. * * @return The blank filler icon. */ protected Icon getBlankIcon() { if (!blankIconInit) { try { Image image = IlvImageUtil.getImageFromFile(AbstractExample.class, BLANK_ICON); blankIcon = new ImageIcon(image); } catch (Exception e) { System.err.println("Warning: error while reading image " + BLANK_ICON); } blankIconInit = true; } return blankIcon; } /** * Calculates whether the specified menu has any menu items with icons. * * @param menu The menu. * @return Whether the menu has any items with icons. */ private boolean computeHasIcons(JMenu menu) { for (int i = 0; i < menu.getMenuComponentCount(); i++) { Component c = menu.getMenuComponent(i); if (c instanceof AbstractButton && ((AbstractButton) c).getIcon() != null) { return true; } } return false; } /** * Sets whether the specified menu has any menu items with icons. * * @param menu The menu. * @param flag Indicates whether the menu has any items with icons. */ protected void setHasIcons(JMenu menu, boolean flag) { menu.putClientProperty(MENU_ITEM_ICONS_KEY, flag); } /** * Returns whether the specified menu has any menu items with icons. * * @param menu The menu. * @return Whether the menu has any items with icons. */ protected boolean hasIcons(JMenu menu) { Boolean flag = (Boolean) menu.getClientProperty(MENU_ITEM_ICONS_KEY); if (flag == null) { flag = computeHasIcons(menu); menu.putClientProperty(MENU_ITEM_ICONS_KEY, flag); } return flag; } /** * Adds the specified action to a menu and returns the created * <code>JMenuItem</code>. * * @param menu The menu. * @param action The action. * @return The menu item. */ protected JMenuItem addAction(JMenu menu, IlvAction action) { return addAction(menu, action, null); } /** * Adds the specified action to a menu and makes it possible to invoke the * action through additional accelerators. (The primary accelerator is * <code>action.getAccelerator()</code>.) * Returns the created <code>JMenuItem</code>. * * @param menu The menu. * @param action The action. * @param additionalAccelerators a set of keystrokes, or <code>null</code>. * @return The menu item. */ protected JMenuItem addAction(JMenu menu, IlvAction action, KeyStroke[] additionalAccelerators) { // Create the menu item from the action. This configures the item text, // icon, and mnemonic. Under JDK 1.4 and later, it also configures the item // tooltip and accelerator keystroke. JMenuItem menuItem = new JMenuItem(action); // Under JDK 1.3 and earlier we must explicitly configure the menu item's // accelerator from the action. KeyStroke accelerator = action.getAccelerator(); if (accelerator != null) { menuItem.setAccelerator(accelerator); } // Enable the additional accelerators. if (additionalAccelerators != null && additionalAccelerators.length > 0) { String name = action.getName(); // Here we assume that different actions have different names. for (KeyStroke ks : additionalAccelerators) { menu.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, name); } menu.getActionMap().put(name, action); } // Under JDK 1.4 and later, explicitly disable the menu item tooltip. menuItem.setToolTipText(null); // If we are about to add the first item with an icon, set all other items // to have a blank icon for proper alignment. if (!hasIcons(menu) && menuItem.getIcon() != null) { for (int i = 0; i < menu.getMenuComponentCount(); i++) { Component c = menu.getMenuComponent(i); if (c instanceof AbstractButton && ((AbstractButton) c).getIcon() != null) { ((AbstractButton) c).setIcon(getBlankIcon()); } } setHasIcons(menu, true); } // If we are about to add an action with no icon to a menu that has icons, // use a blank icon for the menu item so that it is properly aligned. if (hasIcons(menu) && menuItem.getIcon() == null) { menuItem.setIcon(getBlankIcon()); } // Configure the status bar text for the menu item. String longDescription = action.getLongDescription(); if (longDescription == null) { longDescription = " "; } setStatusText(menuItem, longDescription); // Add the item to the menu. menu.add(menuItem); return menuItem; } // ========================================= // Look and Feel // ========================================= /** * Sets the look-and-feel of the example. * * @param laf The look-and-feel. */ protected void setLookAndFeel(UIManager.LookAndFeelInfo laf) { try { UIManager.setLookAndFeel(laf.getClassName()); Container c = rootAncestor; SwingUtilities.updateComponentTreeUI(c); } catch (Exception e) { System.err.println("Failed to install " + laf.getName() + "L&F\n" + e); } } /** * Creates a menu that allows the user to switch between the * available look-and-feels. * * @return The look-and-feel menu. */ protected JMenu createLAFMenu() { JMenu lafMenu = new JMenu("LookAndFeel"); lafMenu.setMnemonic(KeyEvent.VK_O); setHelpID(lafMenu, "Menu.LAF.helpID"); setStatusText(lafMenu, "Selects a Look-and-Feel for the example."); ButtonGroup lafGroup = new ButtonGroup(); ItemListener menuListener = new ItemListener() { Override public void itemStateChanged(ItemEvent evt) { JRadioButtonMenuItem button = (JRadioButtonMenuItem) evt.getSource(); if (button.isSelected()) { UIManager.LookAndFeelInfo selectedLF = (UIManager.LookAndFeelInfo) button.getClientProperty("UIKey"); setLookAndFeel(selectedLF); } } }; // Get the list of installed look-and-feels from the Swing UIManager. UIManager.LookAndFeelInfo[] installedLAFs = UIManager.getInstalledLookAndFeels(); // Add the Kunststoff look-and-feel to the list. List<UIManager.LookAndFeelInfo> lafs = new ArrayList<UIManager.LookAndFeelInfo>(); lafs.addAll(Arrays.asList(installedLAFs)); lafs.add(new UIManager.LookAndFeelInfo("Kunststoff", "com.incors.plaf.kunststoff.KunststoffLookAndFeel")); // Populate the menu with the LAFs. for (UIManager.LookAndFeelInfo lafInfo : lafs) { String lafName = lafInfo.getName(); String lafClassName = lafInfo.getClassName(); boolean lafSupported = false; // We need to verify that the LAF actually exists and is supported. if (!Version.isJava9OrLater()) { try { Class<?> lafClass = Class.forName(lafClassName); LookAndFeel laf = (LookAndFeel) lafClass.getDeclaredConstructor().newInstance(); lafSupported = laf.isSupportedLookAndFeel(); } catch (Throwable t) { LOGGER.debug("AbstractExample.createLAFMenu: ", t); } } else { // For Java 9 or later, it is no longer acceptable to use core reflection to instantiate // LookAndFeel instances, since they are internal to the JDK. We must instead call // method UIManager.createLookAndFeel. An UnsupportedLookAndFeelException being thrown // indicates the LookAndFeel is not supported by the underlying platform. // See: https://bugs.openjdk.java.net/browse/JDK-8178826 try { Method method = UIManager.class.getMethod("createLookAndFeel", String.class); method.invoke(null, lafInfo.getName()); lafSupported = true; // Since no UnsupportedLookAndFeelException was thrown. } catch (Throwable t) { LOGGER.debug("AbstractExample.createLAFMenu: ", t); } } if (lafSupported) { JRadioButtonMenuItem rb = new JRadioButtonMenuItem(lafName); lafMenu.add(rb); rb.setSelected(UIManager.getLookAndFeel().getName().equals(lafName)); rb.putClientProperty("UIKey", lafInfo); rb.addItemListener(menuListener); lafGroup.add(rb); } } return lafMenu; } // ========================================= // Help System // ========================================= /** * An empty help properties dictionary. */ private static final HashMap<String,Object> EMPTY_HELP_PROPERTIES = new HashMap<String,Object>(); /** * Returns the dictionary of Help System properties for this example. Each key * and its corresponding value must be a string. This default implementation * returns an empty dictionary, indicating that the example has no Help System. * <p> * The dictionary should define the following keys in order to setup a * a basic Help System for the example: * <ul> * <li> * HelpSet.name - The name of the help set for the example. This should be * the name of the .HS file, relative to the location of the example's main * class file.</li> * <li> * HelpSet.mainTopic - The top-level help ID for the entire example.</li> * <li> * Gantt.helpID - The help ID for the entire Gantt chart.</li> * <li> * Menu.helpID - The help ID for the entire menu bar.</li> * <li> * Menu.LAF.helpID - The help ID for the LAF Menu.</li> * <li> * Menu.Help.helpID - The help ID for the Help Menu.</li> * <li> * Toolbar.helpID - The help ID for the entire toolbar.</li> * <li> * Customizer.helpID - The help ID for the entire customizer panel.</li> * </ul> * * @return The dictionary of help system properties. */ protected Map<String,Object> getHelpProperties() { return EMPTY_HELP_PROPERTIES; } /** * Returns the value of the specified Help System property. The following * pre-defined keys should be used to setup a basic Help System for the * example: * <ul> * <li> * HelpSet.name - The name of the help set for the example. This should be * the name of the .HS file, relative to the location of the example's main * class file.</li> * <li> * HelpSet.mainTopic - The top-level help ID for the entire example.</li> * <li> * Gantt.helpID - The help ID for the entire Gantt chart.</li> * <li> * Menu.helpID - The help ID for the entire menu bar.</li> * <li> * Menu.LAF.helpID - The help ID for the LAF Menu.</li> * <li> * Menu.Help.helpID - The help ID for the Help Menu.</li> * <li> * Toolbar.helpID - The help ID for the entire toolbar.</li> * <li> * Customizer.helpID - The help ID for the entire customizer panel.</li> * </ul> * * @param key The help ID. * @return The value of the help property. */ protected String getHelpProperty(String key) { Map<String,Object> props = getHelpProperties(); Object objVal = props.get(key); return (objVal instanceof String) ? (String) objVal : null; } /** * Sets the helpID for a component, based upon the specified Help System * property. * * @param comp The component. * @param key The help ID. */ protected void setHelpID(Component comp, String key) { if (!hasHelpSystem() || key == null) { return; } String id = getHelpProperty(key); if (id != null) { getHelpSystem().setHelpIDString(comp, id); } } /** * Sets the helpID for a menu item, based upon the specified Help System * property. * * @param item The menu item. * @param key The help ID. */ protected void setHelpID(MenuItem item, String key) { if (!hasHelpSystem() || key == null) { return; } String id = getHelpProperty(key); if (id != null) { getHelpSystem().setHelpIDString(item, id); } } /** * Returns the class name of the Java Help based help system that should be * used if possible. The default is <code>"shared.help.JavaHelpSystem"</code>. * <p> * This method can be overridden to return the name of a subclass of * <code>shared.help.JavaHelpSystem</code>. */ protected String getJavaHelpSystemClassName() { return "shared.help.JavaHelpSystem"; } /** * Creates the help system. * <p> * This method creates an instance of the class designated by * <code>getJavaHelpSystemClassName()</code> if possible, or an instance of * <code>shared.help.NoHelpSystem</code> otherwise. */ protected HelpSystem createHelpSystem() { String className = getJavaHelpSystemClassName(); try { Class<?> clazz = Class.forName(className); return (HelpSystem) clazz.getDeclaredConstructor().newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (ExceptionInInitializerError e) { e.getException().printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (ClassCastException e) { e.printStackTrace(); } catch (NoClassDefFoundError e) { // Some dependency class is not found in the CLASSPATH. // This happens when jhbasic.jar is not in the CLASSPATH. } catch (LinkageError e) { e.printStackTrace(); } catch (Throwable e) { e.printStackTrace(); } return new NoHelpSystem(); } /** * Initializes the Help System for the example. */ protected void initHelpSystem() { String helpSetName = getHelpProperty("HelpSet.name"); if (helpSetName != null) { helpSystem = createHelpSystem(); helpSystem.init(helpSetName, getClass()); } else { helpSystem = new NoHelpSystem(); } } /** * Returns the help system for the example. * * @return The help system. */ public HelpSystem getHelpSystem() { return helpSystem; } /** * Returns true if the example has a Help System. * * @return Whether the example has a help system. */ public boolean hasHelpSystem() { return !(getHelpSystem() instanceof NoHelpSystem); } /** * Initializes the Help System actions. * * @return Whether the example has a help system that was successfully initialized. */ private boolean initHelpActions() { if (!hasHelpSystem()) { return false; } if (helpAction == null) { final ActionListener helpActionListener = getHelpSystem().createShowHelpActionListener(); helpAction = new IlvAction("Help Topics", null, KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "Help", "Displays help about this example.") { Override public void actionPerformed(ActionEvent event) { helpActionListener.actionPerformed(event); } }; helpAction.setIcon(AbstractExample.class, "images/help.gif"); } if (contextHelpAction == null) { final ActionListener contextHelpActionListener = getHelpSystem().createShowContextSensitiveHelpActionListener(); contextHelpAction = new IlvAction("What's This?", null, KeyStroke.getKeyStroke(KeyEvent.VK_F1, KeyEvent.SHIFT_DOWN_MASK), "Context Sensitive Help", "Displays help about this example.") { Override public void actionPerformed(ActionEvent event) { contextHelpActionListener.actionPerformed(event); } }; contextHelpAction.setIcon(AbstractExample.class, "images/cshelp.gif"); } return true; } /** * Creates the Help menu. This method returns <code>null</code> if the example * does not have a Help System. * * @return The help menu. */ public JMenu createHelpMenu() { if (!initHelpActions()) { return null; } JMenu menu = new JMenu("Help"); menu.setMnemonic(KeyEvent.VK_H); setHelpID(menu, "Menu.Help.helpID"); setStatusText(menu, "Displays help about this example."); JMenuItem helpItem = addAction(menu, helpAction); setHelpID(helpItem, "HelpSet.mainTopic"); addAction(menu, contextHelpAction); return menu; } /** * Populates the specified toolbar with the Help System actions. * * @param toolbar The toolbar. */ protected void populateToolBarHelpActions(JToolBar toolbar) { if (!initHelpActions()) { return; } toolbar.addSeparator(); JButton helpButton = addAction(toolbar, helpAction); setHelpID(helpButton, "HelpSet.mainTopic"); addAction(toolbar, contextHelpAction); } // ========================================= // Colors // ========================================= /** * Shows a modal color-chooser dialog and blocks until the dialog is hidden. * If the user presses the "OK" button, this method hides/disposes the * dialog and returns the selected color. If the user presses the "Cancel" * button or closes the dialog without pressing "OK", this method * hides/disposes the dialog and returns <code>null</code>. * * @param title The title of the dialog. * @param initialColor The initial color set when the color-chooser is shown. * @return The color. */ protected Color chooseColor(String title, Color initialColor) { int alpha = initialColor.getAlpha(); Color newColor = IlvJColorChooser.showDialog(this, title, initialColor); if (newColor != null) { if (newColor.getAlpha() != alpha) { newColor = new Color(newColor.getRed(), newColor.getGreen(), newColor.getBlue(), alpha); } } return newColor; } /** * <code>MenuInfo</code> is an inner class used for displaying information on * menus and menu items. The status text of the menu item is displayed in the * status bar. This class should be registered as a * <code>MenuDragMouseListener</code> * and as a <code>MouseMotionListener</code> with <code>JMenuItem</code>s. It * should be registered as a <code>MenuDragMouseListener</code> and as a * <code>MenuListener</code> with <code>JMenu</code>s. */ class MenuInfo implements MenuDragMouseListener, MenuListener, MouseMotionListener { // Text used to clear the status bar. private static final String NULL_TEXT = " "; // The current text being displayed. private String currentText = NULL_TEXT; // Clears the status bar. private void clearStatus() { JLabel statusBar = getStatusBar(); if (statusBar == null) { return; } if (!NULL_TEXT.equals(currentText)) { currentText = NULL_TEXT; statusBar.setText(NULL_TEXT); } } // Sets the status bar based on the source of the specified event. private void setStatus(EventObject e) { JLabel statusBar = getStatusBar(); if (statusBar == null) { return; } Object source = e.getSource(); if (source instanceof JComponent) { String str = getStatusText((JComponent) source); if (str == null || str.equals("")) { clearStatus(); } else if (!currentText.equals(str)) { currentText = str; statusBar.setText(str); } } else { clearStatus(); } } // A JMenu has been cancelled. Clears the status bar. Override public void menuCanceled(MenuEvent e) { clearStatus(); } // A JMenu has been deselected. Clears the status bar. Override public void menuDeselected(MenuEvent e) { clearStatus(); } // A JMenu has been selected. Sets the status bar to its tooltip text, // if any. Override public void menuSelected(MenuEvent e) { setStatus(e); } // The user has moved the mouse into a menu element. Sets the status bar to // its tooltip text, if any. Override public void menuDragMouseEntered(MenuDragMouseEvent e) { setStatus(e); } // The user has moved the mouse out of a menu element. Clears the status // bar. Override public void menuDragMouseExited(MenuDragMouseEvent e) { clearStatus(); } // The user has dragged the mouse within a menu element. Sets the status // bar to its tooltip text, if any. Override public void menuDragMouseDragged(MenuDragMouseEvent e) { setStatus(e); } // The user has moved the mouse within a menu element. Sets the status bar // to its tooltip text, if any. Override public void mouseMoved(MouseEvent e) { setStatus(e); } Override public void menuDragMouseReleased(MenuDragMouseEvent e) { } Override public void mouseDragged(MouseEvent e) { } } /** * <code>ToolTipUI</code> is an inner class that replaces the standard LAF * delegate for all application tooltips. This LAF serves the purpose of * displaying accelerator bindings correctly. As of JDK 1.2.2, the standard * Metal tooltip UI displays accelerator bindings incorrectly * (see JavaSoft bug #4306876). * First, the Metal tooltip UI attempts to derive the accelerator binding * automatically from the underlying component. Unfortunately, this only * works when the underlying component has a single keystroke binding. * Second, the Metal tooltip UI displays non-ASCII keystrokes incorrectly, * such as VK_DELETE, and so on. * This tooltip UI corrects the first problem by parsing the underlying * component's tooltip text at the first vertical bar. All text before the * delimiter is considered to be the normal tooltip text and all text * following the delimiter is considered to be the accelerator binding text. */ public static class ToolTipUI extends BasicToolTipUI { private static ToolTipUI sharedInstance = new ToolTipUI(); private static final int HORIZONTAL_MARGIN = 3; private static final int VERTICAL_MARGIN = 2; private static final String ACCELERATOR_FONT_KEY = "ACCEL_FONT"; public static final String TIP_DELIMITER = "|"; private static final int PAD_SPACE_BETWEEN_STRINGS = 15; /** * Creates a new <code>AbstractExample.ToolTipUI</code>. */ public ToolTipUI() { } public static ComponentUI createUI(JComponent c) { return sharedInstance; } Override public void installUI(JComponent c) { super.installUI(c); Font f = c.getFont(); // Store a smaller version of the tooltip font as a client property of // the JToolTip itself. This will be used to display the accelerator // text to the right of the normal tooltip text. Font acceleratorFont = new Font(f.getName(), f.getStyle(), f.getSize() - 2); c.putClientProperty(ACCELERATOR_FONT_KEY, acceleratorFont); } /** * Returns the font used to display the accelerator keystroke binding from * the specified <code>JToolTip</code> component. * * @param c The component. * @return The accelerator font. */ public Font getAcceleratorFont(JComponent c) { return (Font) c.getClientProperty(ACCELERATOR_FONT_KEY); } /** * Returns the tooltip text from the specified <code>JToolTip</code> * component. * * @param c The component. * @return The tooltip text. */ public String getTipText(JComponent c) { String text = ((JToolTip) c).getTipText(); if (text == null || text.equals("")) { text = ""; } int index = text.indexOf(TIP_DELIMITER); if (index >= 0) { text = text.substring(0, index); } return text; } /** * Returns the text representation of the accelerator keystroke binding * from the specified <code>JToolTip</code> component. * * @param c The component. * @return The accelerator text. */ public String getAcceleratorText(JComponent c) { String text = ((JToolTip) c).getTipText(); if (text == null || text.equals("")) { text = ""; } int index = text.indexOf(TIP_DELIMITER); if (index < 0) { return ""; } return text.substring(index + 1); } Override public void paint(Graphics g, JComponent c) { Font font = c.getFont(); FontMetrics fm = c.getFontMetrics(font); Dimension size = c.getSize(); Insets insets = c.getInsets(); g.setColor(c.getBackground()); g.fillRect(0, 0, size.width, size.height); g.setColor(c.getForeground()); g.setFont(font); String tipText = getTipText(c); View v = (View) c.getClientProperty("html"); if (v != null) { Rectangle paintTextR = c.getBounds(); paintTextR.x += insets.left; paintTextR.y += insets.top; paintTextR.width -= insets.left + insets.right; paintTextR.height -= insets.top + insets.bottom; v.paint(g, paintTextR); } else { g.drawString(tipText, insets.left + HORIZONTAL_MARGIN, insets.top + VERTICAL_MARGIN + fm.getAscent()); } String accelText = getAcceleratorText(c); if (!accelText.equals("")) { Font acceleratorFont = getAcceleratorFont(c); g.setFont(acceleratorFont); g.drawString(accelText, insets.left + HORIZONTAL_MARGIN + SwingUtilities.computeStringWidth(fm, tipText) + PAD_SPACE_BETWEEN_STRINGS, insets.top + VERTICAL_MARGIN + fm.getAscent()); } } Override public Dimension getPreferredSize(JComponent c) { Font font = c.getFont(); Insets insets = c.getInsets(); Dimension prefSize = new Dimension(insets.left + insets.right, insets.top + insets.bottom); String text = getTipText(c); if (!text.equals("")) { View v = (c != null) ? (View) c.getClientProperty("html") : null; if (v != null) { prefSize.width += (int) v.getPreferredSpan(View.X_AXIS); prefSize.height += (int) v.getPreferredSpan(View.Y_AXIS); } else { FontMetrics fm = c.getFontMetrics(font); prefSize.width += SwingUtilities.computeStringWidth(fm, text) + (2 * HORIZONTAL_MARGIN); prefSize.height += fm.getHeight() + (2 * VERTICAL_MARGIN); } } String accelText = getAcceleratorText(c); if (!accelText.equals("")) { FontMetrics accelFM = c.getFontMetrics(getAcceleratorFont(c)); prefSize.width += SwingUtilities.computeStringWidth(accelFM, accelText) + PAD_SPACE_BETWEEN_STRINGS; } return prefSize; } } }