/*******************************************************************************
* CogTool Copyright Notice and Distribution Terms
* CogTool 1.3, Copyright (c) 2005-2013 Carnegie Mellon University
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* CogTool is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* CogTool is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with CogTool; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* CogTool makes use of several third-party components, with the
* following notices:
*
* Eclipse SWT version 3.448
* Eclipse GEF Draw2D version 3.2.1
*
* Unless otherwise indicated, all Content made available by the Eclipse
* Foundation is provided to you under the terms and conditions of the Eclipse
* Public License Version 1.0 ("EPL"). A copy of the EPL is provided with this
* Content and is also available at http://www.eclipse.org/legal/epl-v10.html.
*
* CLISP version 2.38
*
* Copyright (c) Sam Steingold, Bruno Haible 2001-2006
* This software is distributed under the terms of the FSF Gnu Public License.
* See COPYRIGHT file in clisp installation folder for more information.
*
* ACT-R 6.0
*
* Copyright (c) 1998-2007 Dan Bothell, Mike Byrne, Christian Lebiere &
* John R Anderson.
* This software is distributed under the terms of the FSF Lesser
* Gnu Public License (see LGPL.txt).
*
* Apache Jakarta Commons-Lang 2.1
*
* This product contains software developed by the Apache Software Foundation
* (http://www.apache.org/)
*
* jopt-simple version 1.0
*
* Copyright (c) 2004-2013 Paul R. Holser, Jr.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Mozilla XULRunner 1.9.0.5
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/.
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The J2SE(TM) Java Runtime Environment version 5.0
*
* Copyright 2009 Sun Microsystems, Inc., 4150
* Network Circle, Santa Clara, California 95054, U.S.A. All
* rights reserved. U.S.
* See the LICENSE file in the jre folder for more information.
******************************************************************************/
package edu.cmu.cs.hcii.cogtool.util;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
/**
* Support for creating application menus, both menu bars and pop-up menus.
* <p>
* It is not necessary (and therefore not allowed) to create an instance
* of <code>MenuUtil</code>.
* <p>
* Menu items have both optional mnemonics (a letter in the menu item's text)
* and optional accelerators (a keystroke).
* <p>
* Mnemonics are indicated by an '&' in the name field that causes the
* next character to be the mnemonic.
* Example: "&Quit" means that 'q' is the mnemonic.
* <p>
* An accelerator is the bit-wise OR of zero or more modifier masks
* and a key.
* <code><literal>
* Examples: SWT.NONE | SWT.MOD1 | SWT.MOD2 | 'T',
* SWT.MOD3 | SWT.F2
* SWT.CONTROL | SWT.SHIFT | 'T',
* SWT.ALT | SWT.F2.
* </literal></code><br>
* When using Accelerator keys,
* "command" is standard on the Mac, "control" on Windows.
* There is no META key as in Swing.
* Thus, methods are provided that decide based on the operating system.
*/
public class MenuUtil
{
/**
* Separator for menus
*/
final static public SimpleMenuItemDefinition SEPARATOR =
new SimpleMenuItemDefinition();
protected MenuUtil() { } // Prevent instantiation
/**
* Utility to determine which modifier mask to use based on
* the operating system on which the application is executing.
*
* @author alex
*/
public static int platformControlKey()
{
if (OSUtils.MACOSX) {
return SWT.COMMAND;
}
return SWT.CONTROL;
}
/**
* Utility to determine the other modifier mask to use based on
* the operating system on which the application is executing.
*
* @author alex
*/
public static int notPlatformControlKey()
{
if (OSUtils.MACOSX) {
return SWT.CONTROL;
}
return SWT.COMMAND;
}
/**
* Base class for declarative definitions of menus.
* <p>
* Whether defining a simple menu item or a menu containing
* other items, label components are allowed (localized text name
* and image, both optional).
*
* @author alex, mlh
*/
public static abstract class MenuItemDefinition
{
public String name;
public Image image = null;
/**
* Initializes the label components.
* <p>
* This version initializes the image label component to
* <code>null</code>.
*
* @param inName the localized string label component
* @author alex, mlh
*/
protected MenuItemDefinition(String inName)
{
name = inName;
}
/**
* Initializes the label components.
*
* @param inName the localized string label component
* @param inImage the image label component
* @author alex, mlh
*/
protected MenuItemDefinition(String inName, Image inImage)
{
name = inName;
image = inImage;
}
/**
* Answers whether this instance represents a single menu item
* or a cascading menu.
*
* @return true iff this instance represents a single menu item
*
* @author alex, mlh
*/
public abstract boolean isSingle();
}
/**
* Constant indicating that menu item should be enabled initially.
*/
public static final boolean ENABLED = true;
/**
* Constant indicating that menu item should be disabled initially.
*/
public static final boolean DISABLED = false;
/**
* Class for declarative definitions of singleton menu items.
* <p>
* Each singleton menu item may have an associated accelerator key.
* <p>
* In addition, to facilitate separating controller from view,
* each item can be assigned a <code>ListenerIdentifier</code>
* that may be used by the controller to specify the actions to perform
* when the associated menu item is selected.
* <p>
* A separator is an unselectable menu item that has no label
* components. No action may be associated with a menu separator,
* so no <code>ListenerIdentifier</code> should be assigned.
* See the zero-parameter constructor.
*
* @author alex, mlh
*/
public static class SimpleMenuItemDefinition extends MenuItemDefinition
{
public int accelerator = SWT.NONE;
public int style = SWT.PUSH;
public ListenerIdentifier listenerID;
public boolean enabledInitially = DISABLED;
public boolean selectedInitially = DISABLED;
/**
* Specifies the separator menu item.
*
* @author alex, mlh
*/
public SimpleMenuItemDefinition()
{
super(null);
style = SWT.SEPARATOR;
listenerID = null;
}
/**
* Specifies a menu item with just a text label without
* an accelerator key.
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID)
{
super(inName);
listenerID = inLID;
}
/**
* Specifies a menu item with just a text label and an initial
* enabled state, but without an accelerator key.
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
boolean enabled)
{
super(inName);
listenerID = inLID;
enabledInitially = enabled;
}
/**
* Specifies a menu item with both a text and image label but without
* an accelerator key.
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID)
{
super(inName, inImage);
listenerID = inLID;
}
/**
* Specifies a menu item with both a text and image label, an initial
* enabled state, but without an accelerator key.
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
boolean enabled)
{
super(inName, inImage);
listenerID = inLID;
enabledInitially = enabled;
}
/**
* Specifies a menu item with just a text label with
* an accelerator key.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
int inAccelerator)
{
super(inName);
listenerID = inLID;
accelerator = inAccelerator;
}
/**
* Specifies a menu item with just a text label with
* an accelerator key and initial enabled state.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
int inAccelerator,
boolean enabled)
{
super(inName);
listenerID = inLID;
accelerator = inAccelerator;
enabledInitially = enabled;
}
/**
* Specifies a menu item with both a text and image label, with
* an accelerator key.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
int inAccelerator)
{
super(inName, inImage);
listenerID = inLID;
accelerator = inAccelerator;
}
/**
* Specifies a menu item with both a text and image label, with
* an accelerator key and initial enabled state.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
int inAccelerator,
boolean enabled)
{
super(inName, inImage);
listenerID = inLID;
accelerator = inAccelerator;
enabledInitially = enabled;
}
/**
* Specifies a menu item with just a text label with
* an accelerator key.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle)
{
super(inName);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
}
/**
* Specifies a menu item with a text label, an accelerator key,
* that is enabled,
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle,
boolean inEnabled)
{
super(inName);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
enabledInitially = inEnabled;
}
/**
* Specifies a menu item with a text label, an accelerator key,
* that is enabled, and selected
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* Selected
* Used to cause checkboxes or radio buttons to appear selected
* No effect if the SWT.Style is not Check, or Radio
*
* @param inName the localized string label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @param inEnabled is the menu item visible.
* @param inSelected is the menu item selected.
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle,
boolean inEnabled,
boolean inSelected)
{
super(inName);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
enabledInitially = inEnabled;
selectedInitially = inSelected;
}
/**
* Specifies a menu item with both a text and image label, with
* an accelerator key. Allows setting the SWT style.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle)
{
super(inName, inImage);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
}
/**
* Specifies a menu item with both a text and image label, with
* an accelerator key and initial enabled state.
* Allows setting the SWT style.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle,
boolean enabled)
{
super(inName, inImage);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
enabledInitially = enabled;
}
/**
* Specifies a menu item with both a text and image label, with
* an accelerator key, initial enabled state, and if it is selected
* Allows setting the SWT style.
* <p>
* Specify <code>SWT.NONE</code> for the accelerator key
* if not desired.
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* Selected
* Used to cause checkboxes or radio buttons to appear selected
* No effect if the SWT.Style is not Check, or Radio
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inLID the listener ID for later action assignment
* @param inAccelerator the accelerator's keycode
* @param inStyle the menu item style
* @param enabled whether the item should be enabled initially
* @author alex, mlh
*/
public SimpleMenuItemDefinition(String inName,
Image inImage,
ListenerIdentifier inLID,
int inAccelerator,
int inStyle,
boolean enabled,
boolean selected)
{
super(inName, inImage);
listenerID = inLID;
accelerator = inAccelerator;
style = inStyle;
enabledInitially = enabled;
selectedInitially = selected;
}
/**
* Answers whether this instance represents a single menu item
* or a cascading menu.
* <p>
* Indicates that this instance is a single menu item.
*
* @return true
*
* @author alex, mlh
*/
@Override
public boolean isSingle()
{
return true;
}
}
/**
* Class for declarative definitions of cascading menus.
*
* @author alex, mlh
*/
public static class CascadingMenuItemDefinition extends MenuItemDefinition
{
public MenuItemDefinition[] menuItems;
public Object data;
/**
* Specifies a cascading menu definition with just a text label.
*
* @param inName the localized string label component
* @param inMenuItems the menu items within the cascade
* @author alex, mlh
*/
public CascadingMenuItemDefinition(String inName,
MenuItemDefinition[] inMenuItems)
{
this(inName, inMenuItems, null);
}
public CascadingMenuItemDefinition(String inName,
MenuItemDefinition[] inMenuItems,
Object d)
{
super(inName);
menuItems = inMenuItems;
data = d;
}
/**
* Specifies a cascading menu definition with both a text
* and image label.
*
* @param inName the localized string label component
* @param inImage the image label component
* @param inMenuItems the menu items within the cascade
* @author alex, mlh
*/
public CascadingMenuItemDefinition(String inName,
Image inImage,
MenuItemDefinition[] inMenuItems)
{
super(inName, inImage);
menuItems = inMenuItems;
}
public void setMenuItems(MenuItemDefinition[] inMenuItems)
{
menuItems = inMenuItems;
}
/**
* Answers whether this instance represents a single menu item
* or a cascading menu.
* <p>
* Indicates that this instance is a cascading menu definition.
*
* @return false
*
* @author alex, mlh
*/
@Override
public boolean isSingle()
{
return false;
}
}
/**
* Recursive support method for navigating the tree of
* menu item definitions to construct actual menus and menu items.
* <p>
* Each menu item created is associated with its
* <code>ListenerIdentifier</code>.
*/
protected static void createMenuStep(Shell shell,
Menu parent,
MenuItemDefinition defn,
Boolean availability,
Listener selectionListener,
final ListenerIdentifierMap lIDMap)
{
if (defn.isSingle()) {
SimpleMenuItemDefinition itemDef = (SimpleMenuItemDefinition) defn;
renderShortcut(itemDef);
final MenuItem item = addMenuItem(parent,
itemDef.name,
itemDef.image,
itemDef.style,
itemDef.accelerator,
itemDef.enabledInitially,
itemDef.selectedInitially);
// pull the lid out to a local so the whole SimpleMenuItemDefinition
// doesn't get stored in the dispose listener
final ListenerIdentifier lid = itemDef.listenerID;
if (lid != null) { // avoid separator
// Associate LID with menu item so that it can be used to find
// the associated semantic action by the selectionListener.
item.setData(lid);
item.addListener(SWT.Selection, selectionListener);
lIDMap.addWidget(lid, item, availability);
// If this menu item gets disposed, as for example from a
// dynamic menu, we don't want the LID still pointing at it
item.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e)
{
lIDMap.removeWidget(lid, item);
}
});
}
}
else {
CascadingMenuItemDefinition itemDef =
(CascadingMenuItemDefinition) defn;
MenuItem item =
addMenuItem(parent, itemDef.name, itemDef.image, SWT.CASCADE);
Menu cascadeParent = new Menu(shell, SWT.DROP_DOWN);
item.setMenu(cascadeParent);
item.setData(itemDef.data);
if (itemDef.menuItems != null) {
for (MenuItemDefinition menuItem : itemDef.menuItems) {
createMenuStep(shell,
cascadeParent,
menuItem,
availability,
selectionListener,
lIDMap);
}
}
}
}
/**
* Create a complete menu of the specified style from the given
* definition, associating menu items with their corresponding
* <code>ListenerIdentifier</code>.
* <p>
* <code>rootStyle</code> must be one of <code>SWT.BAR</code>,
* <code>SWT.POP_UP</code>, or <code>SWT.DROP_DOWN</code> optionally OR'ed
* with one of <code>LEFT_TO_RIGHT</code> or <code>RIGHT_TO_LEFT</code>,
* and optionally OR'ed with <code>NO_RADIO_GROUP</code>.
*
* @param shell the application window that is to contain the menu
* @param rootStyle the style of the base menu (such as menu bar, pop up,
* or drop down)
* @param defn the arrangement of the menu items within the menu
* @param availability the availability of the created MenuItem's
* @param selectionListener the selection Listener instance for each
* created MenuItem instance; this Listener
* should use the ListenerIdentifier stored
* in the MenuItem "data" (by calling getData())
* @return the constructed SWT Menu object
* @author alex/mlh
* @see org.eclipse.swt.widgets.Menu
*/
public static Menu createMenu(Shell shell,
int rootStyle,
MenuItemDefinition[] defn,
Boolean availability,
Listener selectionListener,
ListenerIdentifierMap lIDMap)
{
// TODO: check the rootStyle to ensure it's a SWT.BAR or SWT.POPUP???
Menu root = new Menu(shell, rootStyle);
for (MenuItemDefinition element : defn) {
createMenuStep(shell, root, element, availability,
selectionListener, lIDMap);
}
return root;
}
/**
* Add a new item to end of the given menu; used by
* <code>createMenu</code>.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemName the localized text label for the
* <code>MenuItem</code>
* @param menuItemImage the (optional) icon for the constructed
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* @param accelerator the accelerator's keycode (<code>SWT.NONE</code>
* if not desired)
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
String menuItemName,
Image menuItemImage,
int menuItemStyle,
int accelerator,
boolean enabled,
boolean selected)
{
MenuItem mItem = new MenuItem(parentMenu, menuItemStyle);
if (menuItemName != null) {
mItem.setText(menuItemName);
}
if (menuItemImage != null) {
mItem.setImage(menuItemImage);
}
mItem.setAccelerator(accelerator);
mItem.setEnabled(enabled);
mItem.setSelection(selected);
return mItem;
}
/**
* Add a new unselected item without an accelerator to end of the
* given menu; used by <code>createMenu</code>.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemName the localized text label for the
* <code>MenuItem</code>
* @param menuItemImage the (optional) icon for the constructed
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* if not desired)
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
String menuItemName,
Image menuItemImage,
int menuItemStyle)
{
// 0 (ie. SWT.NONE) accelerator means no accelerator. :)
return addMenuItem(parentMenu, menuItemName, menuItemImage,
menuItemStyle, SWT.NONE, true, false);
}
/**
* Add a new unselected item with text label only to end of the given menu.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemName the localized text label for the
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* @param accelerator the accelerator's keycode (<code>SWT.NONE</code>
* if not desired)
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
String menuItemName,
int menuItemStyle,
int accelerator)
{
return addMenuItem(parentMenu, menuItemName, null,
menuItemStyle, accelerator, true, false);
}
/**
* Add a new unselected item with text label only and no accelerator to
* the end of the given menu.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemName the localized text label for the
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
String menuItemName,
int menuItemStyle)
{
// 0 (ie. SWT.NONE) accelerator means no accelerator. :)
return addMenuItem(parentMenu, menuItemName, null,
menuItemStyle, SWT.NONE, true, false);
}
/**
* Add a new unselected item with image only to end of the given menu.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemImage the (optional) icon for the constructed
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* @param accelerator the accelerator's keycode (<code>SWT.NONE</code>
* if not desired)
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
Image menuItemImage,
int menuItemStyle,
int accelerator)
{
return addMenuItem(parentMenu, null, menuItemImage,
menuItemStyle, accelerator, true, false);
}
/**
* Add a new unselected item with image only and no accelerator to end of
* the given menu.
* <p>
* It is expected that the given item name text is localized
* (that is, translated).
* <p>
* Choices for SWT style:
* <code>CHECK, CASCADE, PUSH, RADIO, SEPARATOR</code>
*
* @param parentMenu the menu in which the new
* <code>MenuItem</code> is to reside
* @param menuItemImage the (optional) icon for the constructed
* <code>MenuItem</code>
* @param menuItemStyle the SWT style for the new <code>MenuItem</code>
* @return the constructed <code>MenuItem</code>
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem addMenuItem(Menu parentMenu,
Image menuItemImage,
int menuItemStyle)
{
// 0 (ie. SWT.NONE) accelerator means no accelerator. :)
return addMenuItem(parentMenu, null, menuItemImage,
menuItemStyle, SWT.NONE, true, false);
}
/**
* This function takes arrays of String text labels, styles, accelerators
* to create a set of <code>MenuItem</code> instances.
* <p>
* Deprecated; thought it might be useful, but hasn't come up yet.
* <p>
* The sizes of all arrays must match.
*
* @param parentMenu the menu in which the new
* <code>MenuItems</code> are to reside
* @param menuItemNames the localized text labels for the
* <code>MenuItem</code>s
* @param menuItemStyles the SWT styles for the new <code>MenuItem</code>s
* @param accelerator the accelerator keycodes (<code>SWT.NONE</code>
* if not desired)
* @return the constructed <code>MenuItem</code>s with
* the specified properties
* @author alex/mlh
* @see org.eclipse.swt.widgets.MenuItem
*/
public static MenuItem[] addMenuItemSet(Menu parentMenu,
String[] menuItemNames,
int[] menuItemStyles,
int[] accelerators)
{
int count = menuItemNames.length;
MenuItem[] result = null;
if ((menuItemStyles.length == count) && (accelerators.length == count))
{
result = new MenuItem[count];
for (int i = 0; i < count; i++) {
// ensure each element of menuItems is a string
result[i] = addMenuItem(parentMenu,
menuItemNames[i],
menuItemStyles[i],
accelerators[i]);
}
}
return result;
}
/**
* Ensure when relabeling a menu item that the shortcut (if it exists)
* is displayed.
* <p>
* Shortcut strings are separated from the normal item label by a tab.
*
* @param item the menu to relabel
* @param newLabel the new label for the menu item
*/
public static void relabelItem(MenuItem item, String newLabel)
{
// If running windows, shortcut might already be rendered.
int tabIdx = item.getText().indexOf('\t');
if ((OSUtils.WINDOWS) && (tabIdx >= 0)) {
String shortcut = new String(item.getText().substring(tabIdx));
item.setText(newLabel + shortcut);
}
else {
item.setText(newLabel);
}
}
/**
* Ensure that shortcut(s) (if assigned) are part of the labels
* for the menu items in the given definition.
* <p>
* Shortcut strings are separated from the normal item label by a tab.
*
* @param itemDef the item definition whose label to add the shortcut to
*/
public static void renderShortcut(SimpleMenuItemDefinition itemDef)
{
// Only needed on Windows when the item's label does not already
// have a shortcut indicator.
if ((OSUtils.WINDOWS)
&& (itemDef.name != null)
&& (itemDef.name.indexOf('\t') == -1))
{
// Construct the shortcut string
String shortcut = "\t";
if ((itemDef.accelerator & SWT.CTRL) > 0) {
shortcut += L10N.get("MU.Ctrl+", "Ctrl+");
}
if ((itemDef.accelerator & SWT.ALT) > 0) {
shortcut += L10N.get("MU.Alt+", "Alt+");
}
if ((itemDef.accelerator & SWT.SHIFT) > 0) {
shortcut += L10N.get("MU.Shift+", "Shift+");
}
boolean done = false;
int key = (itemDef.accelerator & SWT.KEY_MASK);
for (int i = 0; i < keyCodes.length; i++) {
if (key == keyCodes[i]) {
shortcut += keyLabels[i];
done = true;
}
}
if (! done) {
shortcut += Character.toUpperCase((char) key);
}
itemDef.name += shortcut;
}
}
// Array of special shortcut keys to determine the index
// into the shortcut key label array.
public static final int[] keyCodes =
{
SWT.ARROW_DOWN,
SWT.ARROW_UP,
SWT.ARROW_LEFT,
SWT.ARROW_RIGHT,
SWT.BREAK,
SWT.BS,
SWT.CR,
SWT.DEL,
SWT.END,
SWT.ESC,
SWT.F1,
SWT.F2,
SWT.F3,
SWT.F4,
SWT.F5,
SWT.F6,
SWT.F7,
SWT.F8,
SWT.F9,
SWT.F10,
SWT.F11,
SWT.F12,
SWT.F13,
SWT.F14,
SWT.F15,
SWT.HELP,
SWT.HOME,
SWT.INSERT,
SWT.KEYPAD_0,
SWT.KEYPAD_1,
SWT.KEYPAD_2,
SWT.KEYPAD_3,
SWT.KEYPAD_4,
SWT.KEYPAD_5,
SWT.KEYPAD_6,
SWT.KEYPAD_7,
SWT.KEYPAD_8,
SWT.KEYPAD_9,
SWT.KEYPAD_ADD,
SWT.KEYPAD_CR,
SWT.KEYPAD_DECIMAL,
SWT.KEYPAD_DIVIDE,
SWT.KEYPAD_EQUAL,
SWT.KEYPAD_MULTIPLY,
SWT.KEYPAD_SUBTRACT,
SWT.PAGE_DOWN,
SWT.PAGE_UP,
SWT.PAUSE,
SWT.PRINT_SCREEN,
' ',
SWT.TAB
};
// Array of shortcut key labels.
public static final String[] keyLabels =
{
L10N.get("MU.Down", "Down"),
L10N.get("MU.Up", "Up"),
L10N.get("MU.Left", "Left"),
L10N.get("MU.Right", "Right"),
L10N.get("MU.Break", "Break"),
L10N.get("MU.Backspace", "Backspace"),
L10N.get("MU.Enter", "Enter"),
L10N.get("MU.Delete", "Delete"),
L10N.get("MU.End", "End"),
L10N.get("MU.Esc", "Esc"),
L10N.get("MU.F1", "F1"),
L10N.get("MU.F2", "F2"),
L10N.get("MU.F3", "F3"),
L10N.get("MU.F4", "F4"),
L10N.get("MU.F5", "F5"),
L10N.get("MU.F6", "F6"),
L10N.get("MU.F7", "F7"),
L10N.get("MU.F8", "F8"),
L10N.get("MU.F9", "F9"),
L10N.get("MU.F10", "F10"),
L10N.get("MU.F11", "F11"),
L10N.get("MU.F12", "F12"),
L10N.get("MU.F13", "F13"),
L10N.get("MU.F14", "F14"),
L10N.get("MU.F15", "F15"),
L10N.get("MU.Help", "Help"),
L10N.get("MU.Home", "Home"),
L10N.get("MU.Insert", "Insert"),
L10N.get("MU.Keypad0", "Keypad0"),
L10N.get("MU.Keypad1", "Keypad1"),
L10N.get("MU.Keypad2", "Keypad2"),
L10N.get("MU.Keypad3", "Keypad3"),
L10N.get("MU.Keypad4", "Keypad4"),
L10N.get("MU.Keypad5", "Keypad5"),
L10N.get("MU.Keypad6", "Keypad6"),
L10N.get("MU.Keypad7", "Keypad7"),
L10N.get("MU.Keypad8", "Keypad8"),
L10N.get("MU.Keypad9", "Keypad9"),
L10N.get("MU.Keypad+", "Keypad+"),
L10N.get("MU.KeypadEnter", "KeypadEnter"),
L10N.get("MU.KeypadPeriod", "KeypadPeriod"),
L10N.get("MU.Keypad/", "Keypad/"),
L10N.get("MU.Keypad=", "Keypad="),
L10N.get("MU.Keypad*", "Keypad*"),
L10N.get("MU.Keypad-", "Keypad-"),
L10N.get("MU.PageDown", "PageDown"),
L10N.get("MU.PageUp", "PageUp"),
L10N.get("MU.Pause", "Pause"),
L10N.get("MU.PrintScreen", "PrintScreen"),
L10N.get("MU.Space", "Space"),
L10N.get("MU.Tab", "Tab")
};
}