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

Last change on this file since 2702 was 2621, checked in by Gubaer, 14 years ago

Moved layer listener management from Layer to MapView
Made sure that listeners also unregister when they register for layer change events.

This will certainly break plugins. Plugin updates will follow later.

  • Property svn:eol-style set to native
File size: 7.6 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.actions;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.util.Collection;
7
8import javax.swing.AbstractAction;
9import javax.swing.JComponent;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.data.SelectionChangedListener;
13import org.openstreetmap.josm.data.osm.DataSet;
14import org.openstreetmap.josm.data.osm.OsmPrimitive;
15import org.openstreetmap.josm.data.osm.PrimitiveDeepCopy;
16import org.openstreetmap.josm.gui.MapView;
17import org.openstreetmap.josm.gui.layer.Layer;
18import org.openstreetmap.josm.gui.layer.OsmDataLayer;
19import org.openstreetmap.josm.tools.Destroyable;
20import org.openstreetmap.josm.tools.ImageProvider;
21import org.openstreetmap.josm.tools.Shortcut;
22
23/**
24 * Base class helper for all Actions in JOSM. Just to make the life easier.
25 *
26 * A JosmAction is a {@see LayerChangeListener} and a {@see SelectionChangedListener}. Upon
27 * a layer change event or a selection change event it invokes {@see #updateEnabled()}.
28 * Subclasses can override {@see #updateEnabled()} in order to update the {@see #isEnabled()}-state
29 * of a JosmAction depending on the {@see #getCurrentDataSet()} and the current layers
30 * (see also {@see #getEditLayer()}).
31 *
32 * destroy() from interface Destroyable is called e.g. for MapModes, when the last layer has
33 * been removed and so the mapframe will be destroyed. For other JosmActions, destroy() may never
34 * be called (currently).
35 *
36 * @author imi
37 */
38abstract public class JosmAction extends AbstractAction implements Destroyable {
39
40 protected Shortcut sc;
41 private LayerChangeAdapter layerChangeAdapter;
42 private SelectionChangeAdapter selectionChangeAdapter;
43
44 public Shortcut getShortcut() {
45 if (sc == null) {
46 sc = Shortcut.registerShortcut("core:none", tr("No Shortcut"), 0, Shortcut.GROUP_NONE);
47 // as this shortcut is shared by all action that don't want to have a shortcut,
48 // we shouldn't allow the user to change it...
49 // this is handled by special name "core:none"
50 }
51 return sc;
52 }
53
54 /**
55 * The new super for all actions.
56 *
57 * Use this super constructor to setup your action. It takes 5 parameters:
58 *
59 * @param name the action's text as displayed on the menu (if it is added to a menu)
60 * @param iconName the filename of the icon to use
61 * @param tooltip a longer description of the action that will be displayed in the tooltip. Please note
62 * that html is not supported for menu actions on some platforms.
63 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
64 * do want a shortcut, remember you can always register it with group=none, so you
65 * won't be assigned a shortcut unless the user configures one. If you pass null here,
66 * the user CANNOT configure a shortcut for your action.
67 * @param register register this action for the toolbar preferences?
68 */
69 public JosmAction(String name, String iconName, String tooltip, Shortcut shortcut, boolean register) {
70 super(name, iconName == null ? null : ImageProvider.get(iconName));
71 setHelpId();
72 sc = shortcut;
73 if (sc != null) {
74 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), name);
75 Main.contentPane.getActionMap().put(name, this);
76 }
77 putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tooltip, sc));
78 putValue("toolbar", iconName);
79 if (register) {
80 Main.toolbar.register(this);
81 }
82 installAdapters();
83 }
84
85 public JosmAction() {
86 setHelpId();
87 installAdapters();
88 }
89
90 public void destroy() {
91 if (sc != null) {
92 Main.contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(sc.getKeyStroke());
93 Main.contentPane.getActionMap().remove(sc.getKeyStroke());
94 }
95 MapView.removeLayerChangeListener(layerChangeAdapter);
96 if (DataSet.selListeners != null) {
97 DataSet.selListeners.remove(selectionChangeAdapter);
98 }
99 }
100
101 /**
102 * needs to be overridden to be useful
103 */
104 public void pasteBufferChanged(PrimitiveDeepCopy newPasteBuffer) {
105 return;
106 }
107
108 /**
109 * needs to be overridden to be useful
110 */
111 public void addListener(JosmAction a) {
112 return;
113 }
114
115 private void setHelpId() {
116 String helpId = "Action/"+getClass().getName().substring(getClass().getName().lastIndexOf('.')+1);
117 if (helpId.endsWith("Action")) {
118 helpId = helpId.substring(0, helpId.length()-6);
119 }
120 putValue("help", helpId);
121 }
122
123 /**
124 * Replies the current edit layer
125 *
126 * @return the current edit layer. null, if no edit layer exists
127 */
128 protected OsmDataLayer getEditLayer() {
129 return Main.main.getEditLayer();
130 }
131
132 /**
133 * Replies the current dataset
134 *
135 * @return the current dataset. null, if no current dataset exists
136 */
137 protected DataSet getCurrentDataSet() {
138 return Main.main.getCurrentDataSet();
139 }
140
141 private void installAdapters() {
142 // make this action listen to layer change and selection change events
143 //
144 layerChangeAdapter = new LayerChangeAdapter();
145 selectionChangeAdapter = new SelectionChangeAdapter();
146 MapView.addLayerChangeListener(layerChangeAdapter);
147 DataSet.selListeners.add(selectionChangeAdapter);
148 initEnabledState();
149 }
150
151 /**
152 * Override in subclasses to init the enabled state of an action when it is
153 * created. Default behaviour is to call {@see #updateEnabledState()}
154 *
155 * @see #updateEnabledState()
156 * @see #updateEnabledState(Collection)
157 */
158 protected void initEnabledState() {
159 updateEnabledState();
160 }
161
162 /**
163 * Override in subclasses to update the enabled state of the action when
164 * something in the JOSM state changes, i.e. when a layer is removed or added.
165 *
166 * See {@see #updateEnabledState(Collection)} to respond to changes in the collection
167 * of selected primitives.
168 *
169 * Default behavior is empty.
170 *
171 * @see #updateEnabledState(Collection)
172 * @see #initEnabledState()
173 */
174 protected void updateEnabledState() {
175 }
176
177 /**
178 * Override in subclasses to update the enabled state of the action if the
179 * collection of selected primitives changes. This method is called with the
180 * new selection. Avoid calling getCurrentDataSet().getSelected() because this
181 * loops over the complete data set.
182 *
183 * @param selection the collection of selected primitives
184 *
185 * @see #updateEnabledState()
186 * @see #initEnabledState()
187 */
188 protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
189 }
190
191 /**
192 * Adapter for layer change events
193 *
194 */
195 private class LayerChangeAdapter implements MapView.LayerChangeListener {
196 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
197 updateEnabledState();
198 }
199
200 public void layerAdded(Layer newLayer) {
201 updateEnabledState();
202 }
203
204 public void layerRemoved(Layer oldLayer) {
205 updateEnabledState();
206 }
207 }
208
209 /**
210 * Adapter for selection change events
211 *
212 */
213 private class SelectionChangeAdapter implements SelectionChangedListener {
214 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
215 updateEnabledState(newSelection);
216 }
217 }
218}
Note: See TracBrowser for help on using the repository browser.