source: josm/trunk/src/org/openstreetmap/josm/actions/JosmAction.java@ 7693

Last change on this file since 7693 was 7693, checked in by stoecker, 10 years ago

see #10684 - no double loading of images, cleanup action icons - menu icon size defaults now to 16x16 (previously most time 24x24) with some errors - maybe 24x24 should be default?

  • Property svn:eol-style set to native
File size: 14.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.event.KeyEvent;
7import java.util.Collection;
8
9import javax.swing.AbstractAction;
10import javax.swing.Icon;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.data.SelectionChangedListener;
14import org.openstreetmap.josm.data.osm.DataSet;
15import org.openstreetmap.josm.data.osm.OsmPrimitive;
16import org.openstreetmap.josm.gui.MapView;
17import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
18import org.openstreetmap.josm.gui.layer.Layer;
19import org.openstreetmap.josm.gui.layer.OsmDataLayer;
20import org.openstreetmap.josm.gui.util.GuiHelper;
21import org.openstreetmap.josm.tools.Destroyable;
22import org.openstreetmap.josm.tools.ImageProvider;
23import org.openstreetmap.josm.tools.Shortcut;
24
25/**
26 * Base class helper for all Actions in JOSM. Just to make the life easier.
27 *
28 * A JosmAction is a {@link LayerChangeListener} and a {@link SelectionChangedListener}. Upon
29 * a layer change event or a selection change event it invokes {@link #updateEnabledState()}.
30 * Subclasses can override {@link #updateEnabledState()} in order to update the {@link #isEnabled()}-state
31 * of a JosmAction depending on the {@link #getCurrentDataSet()} and the current layers
32 * (see also {@link #getEditLayer()}).
33 *
34 * destroy() from interface Destroyable is called e.g. for MapModes, when the last layer has
35 * been removed and so the mapframe will be destroyed. For other JosmActions, destroy() may never
36 * be called (currently).
37 *
38 * @author imi
39 */
40public abstract class JosmAction extends AbstractAction implements Destroyable {
41
42 protected Shortcut sc;
43 private LayerChangeAdapter layerChangeAdapter;
44 private SelectionChangeAdapter selectionChangeAdapter;
45
46 /**
47 * Returns the shortcut for this action.
48 * @return the shortcut for this action, or "No shortcut" if none is defined
49 */
50 public Shortcut getShortcut() {
51 if (sc == null) {
52 sc = Shortcut.registerShortcut("core:none", tr("No Shortcut"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE);
53 // as this shortcut is shared by all action that don't want to have a shortcut,
54 // we shouldn't allow the user to change it...
55 // this is handled by special name "core:none"
56 }
57 return sc;
58 }
59
60 /**
61 * Constructs a {@code JosmAction}.
62 *
63 * @param name the action's text as displayed on the menu (if it is added to a menu)
64 * @param icon the icon to use
65 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
66 * that html is not supported for menu actions on some platforms.
67 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
68 * do want a shortcut, remember you can always register it with group=none, so you
69 * won't be assigned a shortcut unless the user configures one. If you pass null here,
70 * the user CANNOT configure a shortcut for your action.
71 * @param registerInToolbar register this action for the toolbar preferences?
72 * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null
73 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
74 * @deprecated do not pass Icon, pass ImageProvider instead
75 */
76 @Deprecated
77 public JosmAction(String name, Icon icon, String tooltip, Shortcut shortcut, boolean registerInToolbar, String toolbarId, boolean installAdapters) {
78 super(name, icon);
79 setHelpId();
80 sc = shortcut;
81 if (sc != null) {
82 Main.registerActionShortcut(this, sc);
83 }
84 setTooltip(tooltip);
85 if (getValue("toolbar") == null) {
86 putValue("toolbar", toolbarId);
87 }
88 if (registerInToolbar && Main.toolbar != null) {
89 Main.toolbar.register(this);
90 }
91 if (installAdapters) {
92 installAdapters();
93 }
94 }
95
96 /**
97 * Constructs a {@code JosmAction}.
98 *
99 * @param name the action's text as displayed on the menu (if it is added to a menu)
100 * @param icon the icon to use
101 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
102 * that html is not supported for menu actions on some platforms.
103 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
104 * do want a shortcut, remember you can always register it with group=none, so you
105 * won't be assigned a shortcut unless the user configures one. If you pass null here,
106 * the user CANNOT configure a shortcut for your action.
107 * @param registerInToolbar register this action for the toolbar preferences?
108 * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null
109 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
110 * TODO: do not pass Icon, pass ImageProvider instead
111 */
112 public JosmAction(String name, ImageProvider icon, String tooltip, Shortcut shortcut, boolean registerInToolbar, String toolbarId, boolean installAdapters) {
113 super(name);
114 if(icon != null)
115 icon.getResource().getImageIcon(this);
116 setHelpId();
117 sc = shortcut;
118 if (sc != null) {
119 Main.registerActionShortcut(this, sc);
120 }
121 setTooltip(tooltip);
122 if (getValue("toolbar") == null) {
123 putValue("toolbar", toolbarId);
124 }
125 if (registerInToolbar && Main.toolbar != null) {
126 Main.toolbar.register(this);
127 }
128 if (installAdapters) {
129 installAdapters();
130 }
131 }
132
133 /**
134 * The new super for all actions.
135 *
136 * Use this super constructor to setup your action.
137 *
138 * @param name the action's text as displayed on the menu (if it is added to a menu)
139 * @param iconName the filename of the icon to use
140 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
141 * that html is not supported for menu actions on some platforms.
142 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
143 * do want a shortcut, remember you can always register it with group=none, so you
144 * won't be assigned a shortcut unless the user configures one. If you pass null here,
145 * the user CANNOT configure a shortcut for your action.
146 * @param registerInToolbar register this action for the toolbar preferences?
147 * @param toolbarId identifier for the toolbar preferences. The iconName is used, if this parameter is null
148 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
149 */
150 public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar, String toolbarId, boolean installAdapters) {
151 this(name, iconName == null ? null : new ImageProvider(iconName), tooltip, shortcut, registerInToolbar,
152 toolbarId == null ? iconName : toolbarId, installAdapters);
153 }
154
155 /**
156 * Constructs a new {@code JosmAction}.
157 *
158 * Use this super constructor to setup your action.
159 *
160 * @param name the action's text as displayed on the menu (if it is added to a menu)
161 * @param iconName the filename of the icon to use
162 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
163 * that html is not supported for menu actions on some platforms.
164 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
165 * do want a shortcut, remember you can always register it with group=none, so you
166 * won't be assigned a shortcut unless the user configures one. If you pass null here,
167 * the user CANNOT configure a shortcut for your action.
168 * @param registerInToolbar register this action for the toolbar preferences?
169 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
170 */
171 public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar, boolean installAdapters) {
172 this(name, iconName, tooltip, shortcut, registerInToolbar, null, installAdapters);
173 }
174
175 /**
176 * Constructs a new {@code JosmAction}.
177 *
178 * Use this super constructor to setup your action.
179 *
180 * @param name the action's text as displayed on the menu (if it is added to a menu)
181 * @param iconName the filename of the icon to use
182 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
183 * that html is not supported for menu actions on some platforms.
184 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
185 * do want a shortcut, remember you can always register it with group=none, so you
186 * won't be assigned a shortcut unless the user configures one. If you pass null here,
187 * the user CANNOT configure a shortcut for your action.
188 * @param registerInToolbar register this action for the toolbar preferences?
189 */
190 public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean registerInToolbar) {
191 this(name, iconName, tooltip, shortcut, registerInToolbar, null, true);
192 }
193
194 /**
195 * Constructs a new {@code JosmAction}.
196 */
197 public JosmAction() {
198 this(true);
199 }
200
201 /**
202 * Constructs a new {@code JosmAction}.
203 *
204 * @param installAdapters false, if you don't want to install layer changed and selection changed adapters
205 */
206 public JosmAction(boolean installAdapters) {
207 setHelpId();
208 if (installAdapters) {
209 installAdapters();
210 }
211 }
212
213 @Override
214 public void destroy() {
215 if (sc != null) {
216 Main.unregisterActionShortcut(this);
217 }
218 MapView.removeLayerChangeListener(layerChangeAdapter);
219 DataSet.removeSelectionListener(selectionChangeAdapter);
220 }
221
222 private void setHelpId() {
223 String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
224 if (helpId.endsWith("Action")) {
225 helpId = helpId.substring(0, helpId.length()-6);
226 }
227 putValue("help", helpId);
228 }
229
230 /**
231 * Sets the tooltip text of this action.
232 * @param tooltip The text to display in tooltip. Can be {@code null}
233 */
234 public final void setTooltip(String tooltip) {
235 if (tooltip != null) {
236 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
237 }
238 }
239
240 /**
241 * Replies the current edit layer
242 *
243 * @return the current edit layer. null, if no edit layer exists
244 */
245 protected static OsmDataLayer getEditLayer() {
246 return Main.main != null ? Main.main.getEditLayer() : null;
247 }
248
249 /**
250 * Replies the current dataset
251 *
252 * @return the current dataset. null, if no current dataset exists
253 */
254 protected static DataSet getCurrentDataSet() {
255 return Main.main != null ? Main.main.getCurrentDataSet() : null;
256 }
257
258 protected void installAdapters() {
259 // make this action listen to layer change and selection change events
260 //
261 layerChangeAdapter = new LayerChangeAdapter();
262 selectionChangeAdapter = new SelectionChangeAdapter();
263 MapView.addLayerChangeListener(layerChangeAdapter);
264 DataSet.addSelectionListener(selectionChangeAdapter);
265 initEnabledState();
266 }
267
268 /**
269 * Override in subclasses to init the enabled state of an action when it is
270 * created. Default behaviour is to call {@link #updateEnabledState()}
271 *
272 * @see #updateEnabledState()
273 * @see #updateEnabledState(Collection)
274 */
275 protected void initEnabledState() {
276 updateEnabledState();
277 }
278
279 /**
280 * Override in subclasses to update the enabled state of the action when
281 * something in the JOSM state changes, i.e. when a layer is removed or added.
282 *
283 * See {@link #updateEnabledState(Collection)} to respond to changes in the collection
284 * of selected primitives.
285 *
286 * Default behavior is empty.
287 *
288 * @see #updateEnabledState(Collection)
289 * @see #initEnabledState()
290 */
291 protected void updateEnabledState() {
292 }
293
294 /**
295 * Override in subclasses to update the enabled state of the action if the
296 * collection of selected primitives changes. This method is called with the
297 * new selection.
298 *
299 * @param selection the collection of selected primitives; may be empty, but not null
300 *
301 * @see #updateEnabledState()
302 * @see #initEnabledState()
303 */
304 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
305 }
306
307 /**
308 * Adapter for layer change events
309 *
310 */
311 private class LayerChangeAdapter implements MapView.LayerChangeListener {
312 private void updateEnabledStateInEDT() {
313 GuiHelper.runInEDT(new Runnable() {
314 @Override public void run() {
315 updateEnabledState();
316 }
317 });
318 }
319 @Override
320 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
321 updateEnabledStateInEDT();
322 }
323
324 @Override
325 public void layerAdded(Layer newLayer) {
326 updateEnabledStateInEDT();
327 }
328
329 @Override
330 public void layerRemoved(Layer oldLayer) {
331 updateEnabledStateInEDT();
332 }
333 }
334
335 /**
336 * Adapter for selection change events
337 *
338 */
339 private class SelectionChangeAdapter implements SelectionChangedListener {
340 @Override
341 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
342 updateEnabledState(newSelection);
343 }
344 }
345}
Note: See TracBrowser for help on using the repository browser.