Use Actions to simplify the EditorHeader popup menu building

Instead of defining JMenuItems, setting accelerator keys, and attaching
an ActionListener inline, this first defines a list of actions (with a
name, optional accelerator key and using a lambda as the action
listener). Then menu items are added, that simply refer to the
previously defined actions.

The actions are defined in a inner class named Actions, of which one
instance is created. This allows grouping the actions together inside
the `actions` attribute, and allows external access to the actions (in
case the same action is present in multiple menus, or otherwise
performed from other places). This might not be the best way to expose
these actions, and perhaps they should be moved elsewhere, but for now
this seems like a good start.

This adds new helper classes SimpleAction, to allow more consisely
defining Action instances, and a new class Keys, to allow consisely
defining keyboard shortcuts.
This commit is contained in:
Matthijs Kooijman 2015-12-10 14:51:46 +01:00
parent 8c176e7429
commit 957331299b
3 changed files with 228 additions and 52 deletions

View File

@ -22,7 +22,10 @@
*/
package processing.app;
import processing.app.helpers.Keys;
import processing.app.helpers.OSUtils;
import processing.app.helpers.SimpleAction;
import processing.app.tools.MenuScroller;
import static processing.app.I18n.tr;
@ -76,6 +79,31 @@ public class EditorHeader extends JComponent {
int sizeW, sizeH;
int imageW, imageH;
public class Actions {
public final Action newTab = new SimpleAction(tr("New Tab"),
Keys.ctrlShift(KeyEvent.VK_N),
() -> editor.getSketch().handleNewCode());
public final Action renameTab = new SimpleAction(tr("Rename"),
() -> editor.getSketch().handleRenameCode());
public final Action deleteTab = new SimpleAction(tr("Delete"), () -> {
try {
editor.getSketch().handleDeleteCode();
} catch (IOException e) {
e.printStackTrace();
}
});
public final Action prevTab = new SimpleAction(tr("Previous Tab"),
Keys.ctrlAlt(KeyEvent.VK_LEFT),
() -> editor.sketch.handlePrevCode());
public final Action nextTab = new SimpleAction(tr("Next Tab"),
Keys.ctrlAlt(KeyEvent.VK_RIGHT),
() -> editor.sketch.handleNextCode());
}
public Actions actions = new Actions();
public EditorHeader(Editor eddie) {
this.editor = eddie; // weird name for listener
@ -246,59 +274,12 @@ public class EditorHeader extends JComponent {
}
JMenuItem item;
item = Editor.newJMenuItemShift(tr("New Tab"), 'N');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editor.getSketch().handleNewCode();
}
});
menu.add(item);
item = new JMenuItem(tr("Rename"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editor.getSketch().handleRenameCode();
}
});
menu.add(item);
item = new JMenuItem(tr("Delete"));
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
try {
editor.getSketch().handleDeleteCode();
} catch (IOException e) {
e.printStackTrace();
}
}
});
menu.add(item);
menu.add(new JMenuItem(actions.newTab));
menu.add(new JMenuItem(actions.renameTab));
menu.add(new JMenuItem(actions.deleteTab));
menu.addSeparator();
item = new JMenuItem(tr("Previous Tab"));
KeyStroke ctrlAltLeft = KeyStroke
.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
item.setAccelerator(ctrlAltLeft);
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editor.sketch.handlePrevCode();
}
});
menu.add(item);
item = new JMenuItem(tr("Next Tab"));
KeyStroke ctrlAltRight = KeyStroke
.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
item.setAccelerator(ctrlAltRight);
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
editor.sketch.handleNextCode();
}
});
menu.add(item);
menu.add(new JMenuItem(actions.prevTab));
menu.add(new JMenuItem(actions.nextTab));
Sketch sketch = editor.getSketch();
if (sketch != null) {

View File

@ -0,0 +1,83 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Matthijs Kooijman <matthijs@stdin.nl>
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.helpers;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.beans.PropertyChangeEvent;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
/**
* This class contains some keybinding-related helper methods.
*/
public class Keys {
private static final int CTRL = Toolkit.getDefaultToolkit()
.getMenuShortcutKeyMask();
/**
* Creates a KeyCode for the "menu shortcut" + the key passed in. By default,
* the menu shortcut is the ctrl key (hence the method name), but platforms
* might use a different key (like the Apple key on OSX).
*
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
* but this does not work for all characters, so is not recommended).
*/
public static KeyStroke ctrl(int keyCode) {
return KeyStroke.getKeyStroke(keyCode, CTRL);
}
/**
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
* default, the menu shortcut is the ctrl key (hence the method name), but
* platforms might use a different key (like the Apple key on OSX).
*
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
* but this does not work for all characters, so is not recommended).
*/
public static KeyStroke ctrlShift(int keyCode) {
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.SHIFT_MASK);
}
/**
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
* default, the menu shortcut is the ctrl key (hence the method name), but
* platforms might use a different key (like the Apple key on OSX).
*
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
* but this does not work for all characters, so is not recommended).
*/
public static KeyStroke ctrlAlt(int keyCode) {
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.ALT_MASK);
}
}

View File

@ -0,0 +1,112 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Matthijs Kooijman <matthijs@stdin.nl>
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.helpers;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.KeyStroke;
/**
* Class to easily define instances of the Swing Action interface.
*
* When using AbstractAction, you have to create a subclass that implements the
* actionPerformed() method, and sets attributes in the constructor, which gets
* verbose quickly. This class implements actionPerformed for you, and forwards
* it to the ActionListener passed to the constructor (intended to be a lambda
* expression). Additional Action attributes can be set by passing constructor
* arguments.
*
* The name of this class refers to the fact that it's simple to create an
* action using this class, but perhaps a better name can be found for it.
*
* @see javax.swing.Action
*/
public class SimpleAction extends AbstractAction {
private ActionListener listener;
/**
* Version of ActionListener that does not take an ActionEvent as an argument
* This can be used when you do not care about the event itself, just that it
* happened, typically for passing a argumentless lambda or method reference
* to the SimpleAction constructor.
*/
public interface AnonymousActionListener {
public void actionPerformed();
}
public SimpleAction(String name, ActionListener listener) {
this(name, null, null, listener);
}
public SimpleAction(String name, AnonymousActionListener listener) {
this(name, null, null, listener);
}
public SimpleAction(String name, KeyStroke accelerator,
ActionListener listener) {
this(name, null, accelerator, listener);
}
public SimpleAction(String name, KeyStroke accelerator,
AnonymousActionListener listener) {
this(name, null, accelerator, listener);
}
public SimpleAction(String name, String description,
ActionListener listener) {
this(name, description, null, listener);
}
public SimpleAction(String name, String description,
AnonymousActionListener listener) {
this(name, description, null, listener);
}
public SimpleAction(String name, String description, KeyStroke accelerator,
AnonymousActionListener listener) {
this(name, description, accelerator,
(ActionEvent) -> listener.actionPerformed());
}
public SimpleAction(String name, String description, KeyStroke accelerator,
ActionListener listener) {
this.putValue(NAME, name);
this.putValue(SHORT_DESCRIPTION, description);
this.putValue(ACCELERATOR_KEY, accelerator);
this.listener = listener;
}
@Override
public void actionPerformed(ActionEvent e) {
listener.actionPerformed(e);
}
}