Skip to content

Commit 9573312

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 9573312

File tree

3 files changed

+228
-52
lines changed

3 files changed

+228
-52
lines changed

app/src/processing/app/EditorHeader.java

+33-52
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) {
+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Copyright 2015 Matthijs Kooijman <[email protected]>
5+
*
6+
* Arduino is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
package processing.app.helpers;
31+
32+
import java.awt.Toolkit;
33+
import java.awt.event.InputEvent;
34+
import java.beans.PropertyChangeEvent;
35+
36+
import javax.swing.Action;
37+
import javax.swing.JComponent;
38+
import javax.swing.KeyStroke;
39+
40+
/**
41+
* This class contains some keybinding-related helper methods.
42+
*/
43+
public class Keys {
44+
45+
private static final int CTRL = Toolkit.getDefaultToolkit()
46+
.getMenuShortcutKeyMask();
47+
48+
/**
49+
* Creates a KeyCode for the "menu shortcut" + the key passed in. By default,
50+
* the menu shortcut is the ctrl key (hence the method name), but platforms
51+
* might use a different key (like the Apple key on OSX).
52+
*
53+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
54+
* but this does not work for all characters, so is not recommended).
55+
*/
56+
public static KeyStroke ctrl(int keyCode) {
57+
return KeyStroke.getKeyStroke(keyCode, CTRL);
58+
}
59+
60+
/**
61+
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
62+
* default, the menu shortcut is the ctrl key (hence the method name), but
63+
* platforms might use a different key (like the Apple key on OSX).
64+
*
65+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
66+
* but this does not work for all characters, so is not recommended).
67+
*/
68+
public static KeyStroke ctrlShift(int keyCode) {
69+
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.SHIFT_MASK);
70+
}
71+
72+
/**
73+
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
74+
* default, the menu shortcut is the ctrl key (hence the method name), but
75+
* platforms might use a different key (like the Apple key on OSX).
76+
*
77+
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
78+
* but this does not work for all characters, so is not recommended).
79+
*/
80+
public static KeyStroke ctrlAlt(int keyCode) {
81+
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.ALT_MASK);
82+
}
83+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* This file is part of Arduino.
3+
*
4+
* Copyright 2015 Matthijs Kooijman <[email protected]>
5+
*
6+
* Arduino is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
*
20+
* As a special exception, you may use this file as part of a free software
21+
* library without restriction. Specifically, if other files instantiate
22+
* templates or use macros or inline functions from this file, or you compile
23+
* this file and link it with other files to produce an executable, this
24+
* file does not by itself cause the resulting executable to be covered by
25+
* the GNU General Public License. This exception does not however
26+
* invalidate any other reasons why the executable file might be covered by
27+
* the GNU General Public License.
28+
*/
29+
30+
package processing.app.helpers;
31+
32+
import java.awt.event.ActionEvent;
33+
import java.awt.event.ActionListener;
34+
35+
import javax.swing.AbstractAction;
36+
import javax.swing.KeyStroke;
37+
38+
/**
39+
* Class to easily define instances of the Swing Action interface.
40+
*
41+
* When using AbstractAction, you have to create a subclass that implements the
42+
* actionPerformed() method, and sets attributes in the constructor, which gets
43+
* verbose quickly. This class implements actionPerformed for you, and forwards
44+
* it to the ActionListener passed to the constructor (intended to be a lambda
45+
* expression). Additional Action attributes can be set by passing constructor
46+
* arguments.
47+
*
48+
* The name of this class refers to the fact that it's simple to create an
49+
* action using this class, but perhaps a better name can be found for it.
50+
*
51+
* @see javax.swing.Action
52+
*/
53+
public class SimpleAction extends AbstractAction {
54+
private ActionListener listener;
55+
56+
/**
57+
* Version of ActionListener that does not take an ActionEvent as an argument
58+
* This can be used when you do not care about the event itself, just that it
59+
* happened, typically for passing a argumentless lambda or method reference
60+
* to the SimpleAction constructor.
61+
*/
62+
public interface AnonymousActionListener {
63+
public void actionPerformed();
64+
}
65+
66+
public SimpleAction(String name, ActionListener listener) {
67+
this(name, null, null, listener);
68+
}
69+
70+
public SimpleAction(String name, AnonymousActionListener listener) {
71+
this(name, null, null, listener);
72+
}
73+
74+
public SimpleAction(String name, KeyStroke accelerator,
75+
ActionListener listener) {
76+
this(name, null, accelerator, listener);
77+
}
78+
79+
public SimpleAction(String name, KeyStroke accelerator,
80+
AnonymousActionListener listener) {
81+
this(name, null, accelerator, listener);
82+
}
83+
84+
public SimpleAction(String name, String description,
85+
ActionListener listener) {
86+
this(name, description, null, listener);
87+
}
88+
89+
public SimpleAction(String name, String description,
90+
AnonymousActionListener listener) {
91+
this(name, description, null, listener);
92+
}
93+
94+
public SimpleAction(String name, String description, KeyStroke accelerator,
95+
AnonymousActionListener listener) {
96+
this(name, description, accelerator,
97+
(ActionEvent) -> listener.actionPerformed());
98+
}
99+
100+
public SimpleAction(String name, String description, KeyStroke accelerator,
101+
ActionListener listener) {
102+
this.putValue(NAME, name);
103+
this.putValue(SHORT_DESCRIPTION, description);
104+
this.putValue(ACCELERATOR_KEY, accelerator);
105+
this.listener = listener;
106+
}
107+
108+
@Override
109+
public void actionPerformed(ActionEvent e) {
110+
listener.actionPerformed(e);
111+
}
112+
}

0 commit comments

Comments
 (0)