/**
* eAdventure (formerly <e-Adventure> and <e-Game>) is a research project of the
* <e-UCM> research group.
*
* Copyright 2005-2010 <e-UCM> research group.
*
* You can access a list of all the contributors to eAdventure at:
* http://e-adventure.e-ucm.es/contributors
*
* <e-UCM> is a research group of the Department of Software Engineering
* and Artificial Intelligence at the Complutense University of Madrid
* (School of Computer Science).
*
* C Profesor Jose Garcia Santesmases sn,
* 28040 Madrid (Madrid), Spain.
*
* For more info please visit: <http://e-adventure.e-ucm.es> or
* <http://www.e-ucm.es>
*
* ****************************************************************************
*
* This file is part of eAdventure, version 2.0
*
* eAdventure 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 3 of the License, or
* (at your option) any later version.
*
* eAdventure 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 eAdventure. If not, see <http://www.gnu.org/licenses/>.
*/
package es.eucm.ead.editor.view.menu;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.KeyStroke;
import es.eucm.ead.editor.control.Controller;
import es.eucm.ead.editor.control.change.ChangeListener;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JMenuItem;
/**
* An abstract editor menu. All editor menus should descend from this one
* @author mfreire
*/
public abstract class AbstractEditorMenu extends JMenu {
protected Controller controller;
private static int platformMnemonic = Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask();
/**
* Constructor. Should not do any real work (leave that to the initialization)
* @param controller
* @param name
*/
public AbstractEditorMenu(Controller controller, String name) {
super(removeMenuKeyIndicator(name));
this.controller = controller;
setMnemonic(getMenuKeyFromName(name));
}
/**
* Finishes menu setup.
* Should only be called once all controllers have been correctly set up.
*/
public abstract void initialize();
/**
* Returns the keycode for the char after the first '_' in the text.
* @param text
* @return
*/
private static int getMenuKeyFromName(String text) {
int pos = text.indexOf('_');
if (pos == -1 || pos + 1 == text.length()) {
throw new IllegalArgumentException("The string '" + text
+ "' must contain a '_' before its end");
}
char c = text.toLowerCase().charAt(pos + 1);
return getKeyCodeForChar(c);
}
/**
* Java 1.6 does not support 1.7's KeyEvent.getExtendedKeyCodeForChar.
* This is a temporary replacement.
* @param c a char (ideally non-accented)
* @return the corresponding key-code
*/
private static int getKeyCodeForChar(char c) {
char lc = Character.toLowerCase(c);
char uc = Character.toUpperCase(c);
switch (lc) {
case '0':
return KeyEvent.VK_0;
case '1':
return KeyEvent.VK_1;
case '2':
return KeyEvent.VK_2;
case '3':
return KeyEvent.VK_3;
case '4':
return KeyEvent.VK_4;
case '5':
return KeyEvent.VK_5;
case '6':
return KeyEvent.VK_6;
case '7':
return KeyEvent.VK_7;
case '8':
return KeyEvent.VK_8;
case '9':
return KeyEvent.VK_9;
case 'a':
return KeyEvent.VK_A;
case 'b':
return KeyEvent.VK_B;
case 'c':
return KeyEvent.VK_C;
case 'd':
return KeyEvent.VK_D;
case 'e':
return KeyEvent.VK_E;
case 'f':
return KeyEvent.VK_F;
case 'g':
return KeyEvent.VK_G;
case 'h':
return KeyEvent.VK_H;
case 'i':
return KeyEvent.VK_I;
case 'j':
return KeyEvent.VK_J;
case 'k':
return KeyEvent.VK_K;
case 'l':
return KeyEvent.VK_L;
case 'm':
return KeyEvent.VK_M;
case 'n':
return KeyEvent.VK_N;
case 'o':
return KeyEvent.VK_O;
case 'p':
return KeyEvent.VK_P;
case 'q':
return KeyEvent.VK_Q;
case 'r':
return KeyEvent.VK_R;
case 's':
return KeyEvent.VK_S;
case 't':
return KeyEvent.VK_T;
case 'u':
return KeyEvent.VK_U;
case 'v':
return KeyEvent.VK_V;
case 'w':
return KeyEvent.VK_W;
case 'x':
return KeyEvent.VK_X;
case 'y':
return KeyEvent.VK_Y;
case 'z':
return KeyEvent.VK_Z;
// seems to work for most characters in 1.7's ExtendedKeyCodes
default:
return 0x01000000 + uc;
}
}
/**
* Removes all underscores from the text
* @param text
* @return
*/
public static String removeMenuKeyIndicator(String text) {
return text.replaceAll("_", "");
}
/**
* An abstract editor action.
* Registers shortcuts, mnemonics and icons
*/
public static abstract class AbstractEditorAction<E> extends AbstractAction
implements ChangeListener<E> {
/**
* Creates an action without an accelerator
* @param name a string like "_This example", where the
* 't' would be chosen as the mnemonic key, and the underscore would not
* be included in the actual menuitem name
*/
public AbstractEditorAction(String name) {
putValue(NAME, removeMenuKeyIndicator(name));
putValue(MNEMONIC_KEY, getMenuKeyFromName(name));
}
/**
* Creates an action with an accelerator
* @param name a string like "_This example", where the
* 't' would be chosen as the mnemonic key, and the underscore would not
* be included in the actual menuitem name
* @param globalKey
* @param globalModifiers
*/
public AbstractEditorAction(String name, int globalKey,
int globalModifiers) {
putValue(NAME, removeMenuKeyIndicator(name));
putValue(MNEMONIC_KEY, getMenuKeyFromName(name));
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(globalKey,
platformMnemonic | globalModifiers));
}
/**
* Creates an action with an accelerator and icon
*/
/**
* Detailed constructor, with accelerator, mnemonic and icon.
* @param name a string like "_This example", where the
* 't' would be chosen as the mnemonic key, and the underscore would not
* be included in the actual menuitem name
* @param globalKey
* @param globalModifiers
* @param iconUrl
*/
public AbstractEditorAction(String name, int globalKey,
int globalModifiers, String iconUrl) {
putValue(NAME, removeMenuKeyIndicator(name));
putValue(MNEMONIC_KEY, getMenuKeyFromName(name));
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(globalKey,
platformMnemonic | globalModifiers));
putValue(Action.SMALL_ICON, new ImageIcon(ClassLoader
.getSystemClassLoader().getResource(iconUrl)));
}
@Override
public void processChange(E event) {
// default is to do nothing
}
}
/**
* Registers an action with the menu. This creates a suitable entry,
* with key-bindings, shortcuts and everything.
* @param a The action to register.
*/
protected void registerAction(AbstractEditorAction a) {
String name = "" + a.getValue(AbstractAction.NAME);
String desc = "" + a.getValue(AbstractAction.SHORT_DESCRIPTION);
// build menu item
JMenuItem item = new JMenuItem(desc);
item.setAction(a);
add(item);
// register upstream
controller.putAction(name, a);
}
}