Java tutorial
/* * Copyright (c) 1998-2010 The Regents of the University of California. * All rights reserved. * * '$Author: jianwu $' * '$Date: 2013-04-12 17:02:38 -0700 (Fri, 12 Apr 2013) $' * '$Revision: 31915 $' * * Permission is hereby granted, without written agreement and without * license or royalty fees, to use, copy, modify, and distribute this * software and its documentation for any purpose, provided that the above * copyright notice and the following two paragraphs appear in all copies * of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS. * */ package org.kepler.gui; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.lang.reflect.Constructor; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.kepler.build.modules.ModuleTree; import org.kepler.configuration.ConfigurationManager; import org.kepler.configuration.ConfigurationNamespace; import org.kepler.configuration.ConfigurationProperty; import ptolemy.actor.gui.TableauFrame; import ptolemy.gui.MemoryCleaner; import diva.gui.GUIUtilities; import diva.gui.toolbox.JContextMenu; /** * MenuMapper * * A menu creation Runnable that creates and adds a new JMenuBar that provides a * 'view' (in a loose sense) of the ptii menus. It enumerates all the existing * ptii menu items at runtime, and re-uses them, rearranged (and optionally * renamed) - all set via mappings in a localizable resourcebundle properties * (text) file. * * If/when new menu items get added to ptii, they are immediately available for * use here, just by adding the relevant text mapping to the properties file. * * * @author Matthew Brooke * @version $Id: MenuMapper.java 31915 2013-04-13 00:02:38Z jianwu $ * @since * @Pt.ProposedRating * @Pt.AcceptedRating */ public class MenuMapper { // ///////////////////////////////////////////////////////////////// // // public variables //// public final static String MENUITEM_TYPE = "MENUITEM_TYPE"; public final static String CHECKBOX_MENUITEM_TYPE = "CHECKBOX_MENUITEM_TYPE"; public final static String NEW_JMENUITEM_KEY = "NEW_JMENUITEM"; // ///////////////////////////////////////////////////////////////// // // public methods //// /** * Debugging method */ public void printDebugInfo() { System.out.println("_ptiiMenuActionsMap: " + _ptiiMenuActionsMap.size()); for (String s : _ptiiMenuActionsMap.keySet()) { Action a = _ptiiMenuActionsMap.get(s); System.out.println(s + " : " + a.toString()); } } /** * constructor * * @param ptiiMenubar * JMenuBar the existing ptii menubar containing the original * menus * @param tableauFrameInstance * TableauFrame the frame from which the ptii menu bar will be * hidden, and to which the new menu bar will be added */ public MenuMapper(final TableauFrame tableauFrameInstance) { this._tableauFrameInstance = tableauFrameInstance; _mappers.add(this); init(); } public void init() { if (_tableauFrameInstance == null) { log.error( "MenuMapper cannot proceed, due to one or more NULL values:" + "\nptiiMenubar = " + _ptiiMenubar + "\ntableauFrameInstance = " + _tableauFrameInstance + "\ndefaulting to PTII menus"); return; } // First, we need to make sure PTII has finished constructing its menus. // Those menus are created and assembled in a thread that is started in // the // pack() method of ptolemy.gui.Top. As that thread finishes, it adds // the // new ptii JMenuBar to the frame - so we test for that here, and don't // proceed until the frame has the new JMenuBar added // For safety, so we don't have an infinite loop, we also set a safety // counter: // maxWaitMS is the longest the app waits for the ptii // menus to be added, before it continues anyway. final int maxWaitMS = 500; // sleepTimeMS is the amount of time it sleeps per loop: final int sleepTimeMS = 5; // //// final int maxLoops = maxWaitMS / sleepTimeMS; int safetyCounter = 0; while (safetyCounter++ < maxLoops && !_tableauFrameInstance.isMenuPopulated()) { if (isDebugging) { log.debug("Waiting for PTII menus to be created... " + safetyCounter); } try { Thread.sleep(sleepTimeMS); } catch (Exception e) { // ignore } } JMenuBar _keplerMenubar = null; if (_ptiiMenubar == null) { _ptiiMenubar = _tableauFrameInstance.getJMenuBar(); } if (_ptiiMenubar != null) { // gets here if a PTII menubar has been added to frame... // 1) Now PTII has finished constructing its menus, get all // menu items and put them in a Map for easier access later... _ptiiMenuActionsMap = getPTIIMenuActionsMap(); Map<String, Action> ptiiMenuActionsMap = _ptiiMenuActionsMap; // 2) Now we have all the PTII menu items, get the // Kepler-specific menu mappings from the preferences file, // then go thru the Kepler menu mappings and // populate the new menubar with Kepler menus, // creating any new menu items that don't exist yet // this is a Map that will be used to keep track of // what we have added to the menus, and in what order _keplerMenubar = createKeplerMenuBar(ptiiMenuActionsMap); if (_keplerMenubar != null) { // First, look to see if any menus are empty. If // they are, remove the top-level menu from the menubar... // ** NOTE - do these by counting *down* to zero, otherwise the // menus' // indices change dynamically as we remove menus, causing // errors! for (int m = _keplerMenubar.getMenuCount() - 1; m >= 0; m--) { JMenu nextMenu = _keplerMenubar.getMenu(m); if (nextMenu.getMenuComponentCount() < 1) { if (isDebugging) { log.debug("deleting empty menu: " + nextMenu.getText()); } _keplerMenubar.remove(nextMenu); } } // hide the ptii menubar _tableauFrameInstance.hideMenuBar(); // add the new menu bar _tableauFrameInstance.setJMenuBar(_keplerMenubar); } else { log.error("Problem creating Kepler menus - defaulting to PTII menus"); } } else { // gets here if a PTII menubar has *NOT* been added to frame... // Therefore, this frame doesn't have a menubar by default, // so we probably shouldn't add one, for now, at least // hide the ptii menubar (may not be necessary) _tableauFrameInstance.hideMenuBar(); // add the new menu bar (may not be necessary) _tableauFrameInstance.setJMenuBar(null); } } public static Action getActionFor(String key, Map<String, Action> menuActionsMap, TableauFrame tableauFrameInstance) { if (isDebugging) { log.debug("getActionFor(" + key + "," + menuActionsMap.toString() + ")"); } Action action = null; // it's a mapping... // NOTE that all keys in ptiiMenuActionsMap are // uppercase, to make the ptii value entries in the // menu mappings props file case-insensitive String uKey = key.toUpperCase(); if (key.indexOf(MENU_PATH_DELIMITER) > -1) { Object val = menuActionsMap.get(uKey); if (val instanceof Action) { action = (Action) val; } } else { // it's a class or a separator if (uKey.equals(MENU_SEPARATOR_KEY.toUpperCase())) { // it's a separator return null; } else { // it's a class - try to instantiate... Object actionObj = null; boolean actionInitialized = true; try { // create the class String classSearchName = key.trim(); ClassLoader thisClassLoader = MenuMapper.class.getClassLoader(); Class<?> classDefinition = thisClassLoader.loadClass(classSearchName); // add the arg types Class<?>[] args = new Class[] { TableauFrame.class }; // create a constructor Constructor<?> constructor; try { constructor = classDefinition.getConstructor(args); } catch (java.lang.NoSuchMethodException nsme) { args = new Class[] { ptolemy.vergil.basic.BasicGraphFrame.class }; constructor = classDefinition.getConstructor(args); } // set the args Object[] argImp = new Object[] { tableauFrameInstance }; // create the object //if (isDebugging) log.debug("BEFORE"); actionObj = constructor.newInstance(argImp); //if (isDebugging) log.debug("AFTER"); // if the action object is an InitializableAction, try to // initialize it. if (actionObj instanceof InitializableAction) { actionInitialized = ((InitializableAction) actionObj).initialize(menuActionsMap); } } catch (Exception e) { log.warn("Exception trying to create an Action for classname: <" + key + ">:\n" + e.getCause() + " (" + e + ")"); actionObj = null; } if (actionObj == null) { // System.out.println("2Error creating action for class: " + // key); if (isDebugging) { log.error("Problem trying to create an Action for classname: <" + key + ">\nPossible reasons:\n" + "1) Should be a fully-qualified classname, including " + "the package - Check carefully for mistakes.\n" + "2) class must implement javax.swing.Action, and must " + "have a constructor of the form: \n" + " MyConstructor(ptolemy.actor.gui.TableauFrame)\n" + "Returning NULL Action for classname: " + key); } return null; // see if the initialization failed. if so, set the actionObj // to null so this action is not put on the menu bar. } else if (!actionInitialized) { actionObj = null; } action = (Action) actionObj; } } return action; } /** * Recurse through all the submenu heirarchy beneath the passed JMenu * parameter, and for each "leaf node" (ie a menu item that is not a * container for other menu items), add the Action and its menu path to the * passed Map * * @param nextMenuItem * the JMenu to recurse into * @param menuPathBuff * a delimited String representation of the hierarchical "path" * to this menu item. This will be used as the key in the * actionsMap. For example, the "Graph Editor" menu item beneath * the "New" item on the "File" menu would have a menuPath of * File->New->Graph Editor. Delimeter is "->" (no quotes), and * spaces are allowed within menu text strings, but not around * the delimiters; i.e: New->Graph Editor is OK, but File ->New * is not. * @param MENU_PATH_DELIMITER * String * @param actionsMap * the Map containing key => value pairs of the form: menuPath * (as described above) => Action (the javax.swing.Action * assigned to this menu item) */ public static void storePTIIMenuItems(JMenuItem nextMenuItem, StringBuffer menuPathBuff, final String MENU_PATH_DELIMITER, Map<String, Action> actionsMap) { menuPathBuff.append(MENU_PATH_DELIMITER); if (nextMenuItem != null && nextMenuItem.getText() != null) { String str = nextMenuItem.getText(); // do not make the recent files menu item upper case since // it contains paths in the file system. if (menuPathBuff.toString().startsWith("FILE->RECENT FILES->")) { menuPathBuff = new StringBuffer("File->Recent Files->"); } else { str = str.toUpperCase(); } menuPathBuff.append(str); } if (isDebugging) { log.debug(menuPathBuff.toString()); } // System.out.println(menuPathBuff.toString()); if (nextMenuItem instanceof JMenu) { storePTIITopLevelMenus((JMenu) nextMenuItem, menuPathBuff.toString(), MENU_PATH_DELIMITER, actionsMap); } else { Action nextAction = nextMenuItem.getAction(); // if there is no Action, look for an ActionListener // System.out.println("Processing menu " + nextMenuItem.getText()); if (nextAction == null) { final ActionListener[] actionListeners = nextMenuItem.getActionListeners(); // System.out.println("No Action for " + nextMenuItem.getText() // + "; found " + actionListeners.length // + " ActionListeners"); if (actionListeners.length > 0) { if (isDebugging) { log.debug(actionListeners[0].getClass().getName()); } // ASSUMPTION: there is only one ActionListener nextAction = new AbstractAction() { public void actionPerformed(ActionEvent a) { actionListeners[0].actionPerformed(a); } }; // add all these values - @see diva.gui.GUIUtilities nextAction.putValue(Action.NAME, nextMenuItem.getText()); // System.out.println("storing ptII action for menu " + // nextMenuItem.getText()); nextAction.putValue(GUIUtilities.LARGE_ICON, nextMenuItem.getIcon()); nextAction.putValue(GUIUtilities.MNEMONIC_KEY, new Integer(nextMenuItem.getMnemonic())); nextAction.putValue("tooltip", nextMenuItem.getToolTipText()); nextAction.putValue(GUIUtilities.ACCELERATOR_KEY, nextMenuItem.getAccelerator()); nextAction.putValue("menuItem", nextMenuItem); } else { if (isDebugging) { log.warn("No Action or ActionListener found for " + nextMenuItem.getText()); } } } if (!actionsMap.containsValue(nextAction)) { actionsMap.put(menuPathBuff.toString(), nextAction); if (isDebugging) { log.debug(menuPathBuff.toString() + " :: ACTION: " + nextAction); } } } } // ///////////////////////////////////////////////////////////////// // // private methods //// private JMenuBar createKeplerMenuBar(Map<String, Action> ptiiMenuActionsMap) { final LinkedHashMap<String, JMenuItem> keplerMenuMap = new LinkedHashMap<String, JMenuItem>(); final JMenuBar _keplerMenubar = new JMenuBar(); if (isDebugging) { log.debug("***************\nKEPLER MENUS:\n***************\n"); } Iterator<ConfigurationProperty> it = null; try { ConfigurationProperty prop = ConfigurationManager.getInstance().getProperty( ConfigurationManager.getModule("gui"), new ConfigurationNamespace("uiMenuMappings")); if (prop == null) { log.warn("Could not load uiMenuMappings configuration file."); return null; } List<ConfigurationProperty> reposList = prop.getProperties("name", true); it = reposList.iterator(); if (it == null) { log.warn("Menu mappings do not contain any valid assignments"); return null; } separatorJustAdded = false; while (it.hasNext()) { ConfigurationProperty cp = it.next(); String nextKey = cp.getValue(); String nextVal = cp.getParent().getProperty("value").getValue(); ConfigurationProperty moduleProperty = cp.getParent().getProperty("module"); if (moduleProperty != null) { String nextModule = moduleProperty.getValue(); ModuleTree mt = ModuleTree.instance(); if (!mt.contains(nextModule)) { if (isDebugging) { log.debug("Skipping this entry (" + nextKey + ") because '" + nextModule + "' is not active"); } continue; } else if (isDebugging) { log.debug("Processing this entry (" + nextKey + ") explicitly because '" + nextModule + "' is active"); } } else if (isDebugging) { log.debug(nextKey + " has no module associated with it"); } // String nextKey = (String) (it.next()); if (isDebugging) { log.debug("nextKey: " + nextKey); } if (nextKey == null || nextKey.trim().length() < 1) { continue; } if (isDebugging) { log.debug("nextVal: " + nextVal); } if (nextVal == null || nextVal.trim().length() < 1) { log.warn("no menu mapping found for key: " + nextKey); continue; } Action action = null; if (nextKey.indexOf(MENU_SEPARATOR_KEY) < 0) { // if it's the recent files menu item, add all // the existing entries. // NOTE: we can't put the entries in the menu mappings // configuration file since they are dynamic. if (nextVal.equals("File->Recent Files")) { for (Map.Entry<String, Action> entry : ptiiMenuActionsMap.entrySet()) { if (entry.getKey().startsWith("File->Recent Files->")) { addMenuFor(entry.getKey(), entry.getValue(), _keplerMenubar, keplerMenuMap); //System.out.println("adding recent entry: " + entry.getKey()); } } continue; } action = getActionFor(nextVal, ptiiMenuActionsMap, _tableauFrameInstance); if (action == null) { if (isDebugging) { log.warn("null action for value " + nextVal); } continue; } // action exists, and it's not a separator // menuItemCount++; } addMenuFor(nextKey, action, _keplerMenubar, keplerMenuMap); // prevTopLevel // = _keplerMenubar.getMenu(_keplerMenubar.getMenuCount() - // 1).getText(); } } catch (Exception ex) { if (isDebugging) { log.warn("Exception creating Kepler menus: " + ex + "\nDefaulting to PTII menus"); if (isDebugging) { ex.printStackTrace(); } return _keplerMenubar; } } separatorJustAdded = false; if (isDebugging) { log.debug("***************\nEND KEPLER MENUS:\n***************\n"); } return _keplerMenubar; } public Map<String, Action> getPTIIMenuActionsMap() { if (_ptiiMenubar == null) { _ptiiMenubar = _tableauFrameInstance.getJMenuBar(); } if (_ptiiMenuActionsMap == null || _reloadPtolemyMenus) { if (isDebugging) { log.debug("**************\nEXISTING PTII MENUS:\n**************\n"); } // NOTE: use a LinkedHashMap to preserve the order of the // recently opened files list _ptiiMenuActionsMap = new LinkedHashMap<String, Action>(); for (int m = 0; m < _ptiiMenubar.getMenuCount(); m++) { JMenu nextMenu = _ptiiMenubar.getMenu(m); storePTIITopLevelMenus(nextMenu, nextMenu.getText().toUpperCase(), MENU_PATH_DELIMITER, _ptiiMenuActionsMap); } _reloadPtolemyMenus = false; if (isDebugging) { log.debug("\n**************\nEND PTII MENUS:\n*****************\n"); } } return _ptiiMenuActionsMap; } private static void storePTIITopLevelMenus(JMenu nextMenu, String menuPath, final String MENU_PATH_DELIMITER, Map<String, Action> ptiiMenuActionsMap) { int totMenuItems = nextMenu.getMenuComponentCount(); for (int n = 0; n < totMenuItems; n++) { Component nextComponent = nextMenu.getMenuComponent(n); if (nextComponent instanceof JMenuItem) { storePTIIMenuItems((JMenuItem) nextComponent, new StringBuffer(menuPath), MENU_PATH_DELIMITER, ptiiMenuActionsMap); } // (if it's not an instanceof JMenuItem, it must // be a separator, and can therefore be ignored) } } public static JMenuItem addMenuFor(String key, Action action, JComponent topLvlContainer, Map<String, JMenuItem> keplerMenuMap) { if (topLvlContainer == null) { if (isDebugging) { log.debug("NULL container received (eg JMenuBar) - returning NULL"); } return null; } if (key == null) { if (isDebugging) { log.debug("NULL key received"); } return null; } key = key.trim(); if (key.length() < 1) { if (isDebugging) { log.debug("BLANK key received"); } return null; } if (action == null && key.indexOf(MENU_SEPARATOR_KEY) < 0) { if (isDebugging) { log.debug("NULL action received, but was not a separator: " + key); } return null; } if (keplerMenuMap.containsKey(key)) { if (isDebugging) { log.debug("Menu already added; skipping: " + key); } return null; } // split delimited parts and ensure menus all exist String[] menuLevel = key.split(MENU_PATH_DELIMITER); int totLevels = menuLevel.length; // create a menu for each "menuLevel" if it doesn't already exist final StringBuffer nextLevelBuff = new StringBuffer(); String prevLevelStr = null; JMenuItem leafMenuItem = null; for (int levelIdx = 0; levelIdx < totLevels; levelIdx++) { // save previous value prevLevelStr = nextLevelBuff.toString(); String nextLevelStr = menuLevel[levelIdx]; // get the index of the first MNEMONIC_SYMBOL int mnemonicIdx = nextLevelStr.indexOf(MNEMONIC_SYMBOL); char mnemonicChar = 0; // if an MNEMONIC_SYMBOL exists, remove all underscores. Then, idx // of // first underscore becomes idx of letter it used to precede - this // is the mnemonic letter if (mnemonicIdx > -1) { nextLevelStr = nextLevelStr.replaceAll(MNEMONIC_SYMBOL, ""); mnemonicChar = nextLevelStr.charAt(mnemonicIdx); } if (levelIdx != 0) { nextLevelBuff.append(MENU_PATH_DELIMITER); } nextLevelBuff.append(nextLevelStr); // don't add multiple separators together... if (nextLevelStr.indexOf(MENU_SEPARATOR_KEY) > -1) { if (separatorJustAdded == false) { // Check if we're at the top level, since this makes sense // only for // context menu - we can't add a separator to a JMenuBar if (levelIdx == 0) { if (topLvlContainer instanceof JContextMenu) { ((JContextMenu) topLvlContainer).addSeparator(); } } else { JMenu parent = (JMenu) keplerMenuMap.get(prevLevelStr); if (parent != null) { if (parent.getMenuComponentCount() < 1) { if (isDebugging) { log.debug("------ NOT adding separator to parent " + parent.getText() + ", since it does not contain any menu items"); } } else { if (isDebugging) { log.debug("------ adding separator to parent " + parent.getText()); } // add separator to parent parent.addSeparator(); separatorJustAdded = true; } } } } } else if (!keplerMenuMap.containsKey(nextLevelBuff.toString())) { // If menu has not already been created, we need // to create it and then add it to the parent level... JMenuItem menuItem = null; // if we're at a "leaf node" - need to create a JMenuItem if (levelIdx == totLevels - 1) { // save old display name to use as actionCommand on // menuitem, // since some parts of PTII still // use "if (actionCommand.equals("SaveAs")) {..." etc String oldDisplayName = (String) action.getValue(Action.NAME); // action.putValue(Action.NAME, nextLevelStr); if (mnemonicChar > 0) { action.putValue(GUIUtilities.MNEMONIC_KEY, new Integer(mnemonicChar)); } // Now we look to see if it's a checkbox // menu item, or just a regular one String menuItemType = (String) (action.getValue(MENUITEM_TYPE)); if (menuItemType != null && menuItemType == CHECKBOX_MENUITEM_TYPE) { menuItem = new JCheckBoxMenuItem(action); } else { menuItem = new JMenuItem(action); } // -------------------------------------------------------------- /** @todo - setting menu names - TEMPORARY FIX - FIXME */ // Currently, if we use the "proper" way of setting menu // names - // ie by using action.putValue(Action.NAME, "somename");, // then // the name appears on the port buttons on the toolbar, // making // them huge. As a temporary stop-gap, I am just setting the // new // display name using setText() instead of // action.putValue(.., // but this needs to be fixed elsewhere - we want to be able // to // use action.putValue(Action.NAME (ie uncomment the line // above // that reads: // action.putValue(Action.NAME, nextLevelStr); // and delete the line below that reads: // menuItem.setText(nextLevelStr); // otherwise this may bite us in future... menuItem.setText(nextLevelStr); // -------------------------------------------------------------- // set old display name as actionCommand on // menuitem, for ptii backward-compatibility menuItem.setActionCommand(oldDisplayName); // add JMenuItem to the Action, so it can be accessed by // Action code action.putValue(NEW_JMENUITEM_KEY, menuItem); leafMenuItem = menuItem; } else { // if we're *not* at a "leaf node" - need to create a JMenu menuItem = new JMenu(nextLevelStr); if (mnemonicChar > 0) { menuItem.setMnemonic(mnemonicChar); } } // level 0 is a special case, since the container (JMenuBar or // JContextMenu) is not a JMenu or a JMenuItem, so we can't // use the same code to add child to parent... if (levelIdx == 0) { if (topLvlContainer instanceof JMenuBar) { // this handles JMenuBar menus ((JMenuBar) topLvlContainer).add(menuItem); } else if (topLvlContainer instanceof JContextMenu) { // this handles popup context menus ((JContextMenu) topLvlContainer).add(menuItem); } // add to Map keplerMenuMap.put(nextLevelBuff.toString(), menuItem); separatorJustAdded = false; } else { JMenu parent = (JMenu) keplerMenuMap.get(prevLevelStr); if (parent != null) { // add to parent parent.add(menuItem); // add to Map keplerMenuMap.put(nextLevelBuff.toString(), menuItem); separatorJustAdded = false; } else { if (isDebugging) { log.debug("Parent menu is NULL" + prevLevelStr); } } } } } return leafMenuItem; } public void clear() { /*int removed =*/ MemoryCleaner.removeActionListeners(_ptiiMenubar); //System.out.println("MenuMapper menubar action listeners removed: " + removed); _ptiiMenuActionsMap.clear(); _tableauFrameInstance = null; _mappers.remove(this); } /** Remap all open menubars. */ public static void reloadAllMenubars() { for (MenuMapper mapper : _mappers) { mapper.reloadPtolemyMenus(); } } /** Remap the menu. */ public void reloadPtolemyMenus() { _reloadPtolemyMenus = true; init(); _tableauFrameInstance.validate(); } // ///////////////////////////////////////////////////////////////// // // private variables //// private static final Log log = LogFactory.getLog(MenuMapper.class.getName()); private static final boolean isDebugging = log.isDebugEnabled(); private JMenuBar _ptiiMenubar; private TableauFrame _tableauFrameInstance; private Map<String, Action> _ptiiMenuActionsMap; private static boolean separatorJustAdded = false; // NOTE - MUST NOT contain the char defined in MNEMONIC_SYMBOL, // or the String defined as MENU_PATH_DELIMITER public static final String MENU_PATH_DELIMITER = "->"; // NOTE - MUST NOT contain the String defined in MNEMONIC_SYMBOL, // or the String defined as MENU_PATH_DELIMITER public static final String MENU_SEPARATOR_KEY = "MENU_SEPARATOR"; // NOTE - MUST NOT match the String defined as MENU_PATH_DELIMITER, // or the String defined as MENU_SEPARATOR_KEY public static final String MNEMONIC_SYMBOL = "~"; /** A collection of all MenuMapper objects. */ private static Set<MenuMapper> _mappers = Collections.synchronizedSet(new HashSet<MenuMapper>()); /** If true, reload the Ptolemy menu. */ private boolean _reloadPtolemyMenus = false; }