Skip to content

Commit f1838f2

Browse files
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.
1 parent 8c176e7 commit f1838f2

File tree

3 files changed

+170
-52
lines changed

3 files changed

+170
-52
lines changed

app/src/processing/app/EditorHeader.java

Lines changed: 33 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@
2222
*/
2323

2424
package processing.app;
25+
26+
import processing.app.helpers.Keys;
2527
import processing.app.helpers.OSUtils;
28+
import processing.app.helpers.SimpleAction;
2629
import processing.app.tools.MenuScroller;
2730
import static processing.app.I18n.tr;
2831

@@ -76,6 +79,31 @@ public class EditorHeader extends JComponent {
7679
int sizeW, sizeH;
7780
int imageW, imageH;
7881

82+
public class Actions {
83+
public final Action newTab = new SimpleAction(tr("New Tab"),
84+
Keys.ctrlShift(KeyEvent.VK_N),
85+
() -> editor.getSketch().handleNewCode());
86+
87+
public final Action renameTab = new SimpleAction(tr("Rename"),
88+
() -> editor.getSketch().handleRenameCode());
89+
90+
public final Action deleteTab = new SimpleAction(tr("Delete"), () -> {
91+
try {
92+
editor.getSketch().handleDeleteCode();
93+
} catch (IOException e) {
94+
e.printStackTrace();
95+
}
96+
});
97+
98+
public final Action prevTab = new SimpleAction(tr("Previous Tab"),
99+
Keys.ctrlAlt(KeyEvent.VK_LEFT),
100+
() -> editor.sketch.handlePrevCode());
101+
102+
public final Action nextTab = new SimpleAction(tr("Next Tab"),
103+
Keys.ctrlAlt(KeyEvent.VK_RIGHT),
104+
() -> editor.sketch.handleNextCode());
105+
}
106+
public Actions actions = new Actions();
79107

80108
public EditorHeader(Editor eddie) {
81109
this.editor = eddie; // weird name for listener
@@ -246,59 +274,12 @@ public void rebuildMenu() {
246274
}
247275
JMenuItem item;
248276

249-
item = Editor.newJMenuItemShift(tr("New Tab"), 'N');
250-
item.addActionListener(new ActionListener() {
251-
public void actionPerformed(ActionEvent e) {
252-
editor.getSketch().handleNewCode();
253-
}
254-
});
255-
menu.add(item);
256-
257-
item = new JMenuItem(tr("Rename"));
258-
item.addActionListener(new ActionListener() {
259-
public void actionPerformed(ActionEvent e) {
260-
editor.getSketch().handleRenameCode();
261-
}
262-
});
263-
menu.add(item);
264-
265-
item = new JMenuItem(tr("Delete"));
266-
item.addActionListener(new ActionListener() {
267-
public void actionPerformed(ActionEvent event) {
268-
try {
269-
editor.getSketch().handleDeleteCode();
270-
} catch (IOException e) {
271-
e.printStackTrace();
272-
}
273-
}
274-
});
275-
menu.add(item);
276-
277+
menu.add(new JMenuItem(actions.newTab));
278+
menu.add(new JMenuItem(actions.renameTab));
279+
menu.add(new JMenuItem(actions.deleteTab));
277280
menu.addSeparator();
278-
279-
item = new JMenuItem(tr("Previous Tab"));
280-
KeyStroke ctrlAltLeft = KeyStroke
281-
.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
282-
item.setAccelerator(ctrlAltLeft);
283-
item.addActionListener(new ActionListener() {
284-
@Override
285-
public void actionPerformed(ActionEvent e) {
286-
editor.sketch.handlePrevCode();
287-
}
288-
});
289-
menu.add(item);
290-
291-
item = new JMenuItem(tr("Next Tab"));
292-
KeyStroke ctrlAltRight = KeyStroke
293-
.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
294-
item.setAccelerator(ctrlAltRight);
295-
item.addActionListener(new ActionListener() {
296-
@Override
297-
public void actionPerformed(ActionEvent e) {
298-
editor.sketch.handleNextCode();
299-
}
300-
});
301-
menu.add(item);
281+
menu.add(new JMenuItem(actions.prevTab));
282+
menu.add(new JMenuItem(actions.nextTab));
302283

303284
Sketch sketch = editor.getSketch();
304285
if (sketch != null) {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package processing.app.helpers;
2+
3+
import java.awt.Toolkit;
4+
import java.awt.event.InputEvent;
5+
import java.beans.PropertyChangeEvent;
6+
7+
import javax.swing.Action;
8+
import javax.swing.JComponent;
9+
import javax.swing.KeyStroke;
10+
11+
/**
12+
* This class contains some keybinding-related helper methods.
13+
*/
14+
public class Keys {
15+
16+
private static final int CTRL = Toolkit.getDefaultToolkit()
17+
.getMenuShortcutKeyMask();
18+
19+
/**
20+
* Creates a KeyCode for the "menu shortcut" + the key passed in. By default,
21+
* the menu shortcut is the ctrl key (hence the method name), but platforms
22+
* might use a different key (like the Apple key on OSX).
23+
*
24+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
25+
* but this does not work for all characters, so is not recommended).
26+
*/
27+
public static KeyStroke ctrl(int keyCode) {
28+
return KeyStroke.getKeyStroke(keyCode, CTRL);
29+
}
30+
31+
/**
32+
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
33+
* default, the menu shortcut is the ctrl key (hence the method name), but
34+
* platforms might use a different key (like the Apple key on OSX).
35+
*
36+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
37+
* but this does not work for all characters, so is not recommended).
38+
*/
39+
public static KeyStroke ctrlShift(int keyCode) {
40+
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.SHIFT_MASK);
41+
}
42+
43+
/**
44+
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
45+
* default, the menu shortcut is the ctrl key (hence the method name), but
46+
* platforms might use a different key (like the Apple key on OSX).
47+
*
48+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
49+
* but this does not work for all characters, so is not recommended).
50+
*/
51+
public static KeyStroke ctrlAlt(int keyCode) {
52+
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.ALT_MASK);
53+
}
54+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package processing.app.helpers;
2+
3+
import java.awt.event.ActionEvent;
4+
import java.awt.event.ActionListener;
5+
6+
import javax.swing.AbstractAction;
7+
import javax.swing.KeyStroke;
8+
9+
/**
10+
* Class to easily define instances of the Swing Action interface.
11+
*
12+
* When using AbstractAction, you have to create a subclass that implements the
13+
* actionPerformed() method, and sets attributes in the constructor, which gets
14+
* verbose quickly. This class implements actionPerformed for you, and forwards
15+
* it to the ActionListener passed to the constructor (intended to be a lambda
16+
* expression). Additional Action attributes can be set by passing constructor
17+
* arguments.
18+
*
19+
* The name of this class refers to the fact that it's simple to create an
20+
* action using this class, but perhaps a better name can be found for it.
21+
*
22+
* @see javax.swing.Action
23+
*/
24+
public class SimpleAction extends AbstractAction {
25+
private ActionListener listener;
26+
27+
/**
28+
* Version of ActionListener that does not take an ActionEvent as an argument
29+
* This can be used when you do not care about the event itself, just that it
30+
* happened, typically for passing a argumentless lambda or method reference
31+
* to the SimpleAction constructor.
32+
*/
33+
public interface AnonymousActionListener {
34+
public void actionPerformed();
35+
}
36+
37+
public SimpleAction(String name, ActionListener listener) {
38+
this(name, null, null, listener);
39+
}
40+
41+
public SimpleAction(String name, AnonymousActionListener listener) {
42+
this(name, null, null, listener);
43+
}
44+
45+
public SimpleAction(String name, KeyStroke accelerator,
46+
ActionListener listener) {
47+
this(name, null, accelerator, listener);
48+
}
49+
50+
public SimpleAction(String name, KeyStroke accelerator,
51+
AnonymousActionListener listener) {
52+
this(name, null, accelerator, listener);
53+
}
54+
55+
public SimpleAction(String name, String description,
56+
ActionListener listener) {
57+
this(name, description, null, listener);
58+
}
59+
60+
public SimpleAction(String name, String description,
61+
AnonymousActionListener listener) {
62+
this(name, description, null, listener);
63+
}
64+
65+
public SimpleAction(String name, String description, KeyStroke accelerator,
66+
AnonymousActionListener listener) {
67+
this(name, description, accelerator,
68+
(ActionEvent) -> listener.actionPerformed());
69+
}
70+
71+
public SimpleAction(String name, String description, KeyStroke accelerator,
72+
ActionListener listener) {
73+
this.putValue(NAME, name);
74+
this.putValue(SHORT_DESCRIPTION, description);
75+
this.putValue(ACCELERATOR_KEY, accelerator);
76+
this.listener = listener;
77+
}
78+
79+
@Override
80+
public void actionPerformed(ActionEvent e) {
81+
listener.actionPerformed(e);
82+
}
83+
}

0 commit comments

Comments
 (0)