source: josm/trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java

Last change on this file was 18759, checked in by taylor.smock, 11 months ago

Fix #22279: Add new split mode for quick splitting of ways (patch by Woazboat, modified)

Modifications are as follows:

  • Simplify/inline some variables
  • Move an inner class used only in a class that it is not in into the appropriate class
  • Fix a pre-existing bug where InputEvent.META_MASK would not be mapped to InputEvent.META_DOWN_MASK
  • Override some additional methods in SplitMode (layerIsSupported and getModeHelpText)
  • Property svn:eol-style set to native
File size: 8.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.actions.mapmode;
3
4import java.awt.Cursor;
5import java.awt.event.ActionEvent;
6import java.awt.event.InputEvent;
7import java.awt.event.MouseEvent;
8import java.awt.event.MouseListener;
9import java.awt.event.MouseMotionListener;
10
11import javax.swing.Action;
12
13import org.openstreetmap.josm.actions.JosmAction;
14import org.openstreetmap.josm.gui.MainApplication;
15import org.openstreetmap.josm.gui.MapFrame;
16import org.openstreetmap.josm.gui.layer.Layer;
17import org.openstreetmap.josm.gui.layer.OsmDataLayer;
18import org.openstreetmap.josm.spi.preferences.Config;
19import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent;
20import org.openstreetmap.josm.spi.preferences.PreferenceChangedListener;
21import org.openstreetmap.josm.tools.ImageProvider;
22import org.openstreetmap.josm.tools.Logging;
23import org.openstreetmap.josm.tools.PlatformHook;
24import org.openstreetmap.josm.tools.PlatformManager;
25import org.openstreetmap.josm.tools.Shortcut;
26
27/**
28 * A class implementing MapMode is able to be selected as an mode for map editing.
29 * As example scrolling the map is a MapMode, connecting Nodes to new Ways is another.
30 *
31 * MapModes should register/deregister all necessary listeners on the map's view control.
32 */
33public abstract class MapMode extends JosmAction implements MouseListener, MouseMotionListener, PreferenceChangedListener {
34 protected final Cursor cursor;
35 protected boolean ctrl;
36 protected boolean alt;
37 protected boolean shift;
38 /**
39 * {@code true} if the meta key was pressed (the "Windows" key or the Mac "Command" key)
40 * @since 18456
41 */
42 protected boolean meta;
43 /**
44 * {@code true} if the platform specific menu key was pressed ("ctrl" on Linux/Windows, "cmd" on Mac)
45 * @see PlatformHook#getMenuShortcutKeyMaskEx()
46 * @since 18456
47 */
48 protected boolean platformMenuShortcutKeyMask;
49
50 /**
51 * Constructor for mapmodes without a menu
52 * @param name the action's text
53 * @param iconName icon filename in {@code mapmode} directory
54 * @param tooltip a longer description of the action that will be displayed in the tooltip.
55 * @param shortcut a ready-created shortcut object or null if you don't want a shortcut.
56 * @param cursor cursor displayed when map mode is active
57 * @since 11713
58 */
59 protected MapMode(String name, String iconName, String tooltip, Shortcut shortcut, Cursor cursor) {
60 super(name, "mapmode/"+iconName, tooltip, shortcut, false);
61 this.cursor = cursor;
62 putValue("active", Boolean.FALSE);
63 }
64
65 /**
66 * Constructor for mapmodes with a menu (no shortcut will be registered)
67 * @param name the action's text
68 * @param iconName icon filename in {@code mapmode} directory
69 * @param tooltip a longer description of the action that will be displayed in the tooltip.
70 * @param cursor cursor displayed when map mode is active
71 * @since 11713
72 */
73 protected MapMode(String name, String iconName, String tooltip, Cursor cursor) {
74 putValue(NAME, name);
75 new ImageProvider("mapmode", iconName).getResource().attachImageIcon(this);
76 putValue(SHORT_DESCRIPTION, tooltip);
77 this.cursor = cursor;
78 }
79
80 /**
81 * Makes this map mode active.
82 */
83 public void enterMode() {
84 Logging.debug("Entering map mode: {0}", getValue(Action.NAME));
85 putValue("active", Boolean.TRUE);
86 Config.getPref().addPreferenceChangeListener(this);
87 readPreferences();
88 MainApplication.getMap().mapView.setNewCursor(cursor, this);
89 MainApplication.getMap().statusLine.setAutoLength(true);
90 updateStatusLine();
91 }
92
93 /**
94 * Makes this map mode inactive.
95 */
96 public void exitMode() {
97 Logging.debug("Exiting map mode: {0}", getValue(Action.NAME));
98 putValue("active", Boolean.FALSE);
99 Config.getPref().removePreferenceChangeListener(this);
100 MainApplication.getMap().mapView.resetCursor(this);
101 MainApplication.getMap().statusLine.setAutoLength(true);
102 }
103
104 protected void updateStatusLine() {
105 MapFrame map = MainApplication.getMap();
106 if (map != null && map.statusLine != null) {
107 map.statusLine.setHelpText(getModeHelpText());
108 map.statusLine.repaint();
109 }
110 }
111
112 /**
113 * Returns a short translated help message describing how this map mode can be used, to be displayed in status line.
114 * @return a short translated help message describing how this map mode can be used
115 */
116 public String getModeHelpText() {
117 return "";
118 }
119
120 protected void readPreferences() {}
121
122 /**
123 * Call selectMapMode(this) on the parent mapFrame.
124 */
125 @Override
126 public void actionPerformed(ActionEvent e) {
127 if (MainApplication.isDisplayingMapView()) {
128 MainApplication.getMap().selectMapMode(this);
129 }
130 }
131
132 /**
133 * Determines if layer {@code l} is supported by this map mode.
134 * By default, all tools will work with all layers.
135 * Can be overwritten to require a special type of layer
136 * @param l layer
137 * @return {@code true} if the layer is supported by this map mode
138 */
139 public boolean layerIsSupported(Layer l) {
140 return l != null;
141 }
142
143 /**
144 * Update internal ctrl, alt, shift mask from given input event.
145 * @param e input event
146 */
147 protected void updateKeyModifiers(InputEvent e) {
148 updateKeyModifiersEx(e.getModifiersEx());
149 }
150
151 /**
152 * Update internal ctrl, alt, shift mask from given mouse event.
153 * @param e mouse event
154 */
155 protected void updateKeyModifiers(MouseEvent e) {
156 updateKeyModifiersEx(e.getModifiersEx());
157 }
158
159 /**
160 * Update internal ctrl, alt, shift mask from given action event.
161 * @param e action event
162 * @since 12526
163 */
164 protected void updateKeyModifiers(ActionEvent e) {
165 // ActionEvent does not have a getModifiersEx() method like other events :(
166 updateKeyModifiersEx(mapOldModifiers(e.getModifiers()));
167 }
168
169 /**
170 * Update internal ctrl, alt, shift, meta mask from given extended modifiers mask.
171 * @param modifiers event extended modifiers mask
172 * @since 12517
173 */
174 protected void updateKeyModifiersEx(int modifiers) {
175 ctrl = (modifiers & InputEvent.CTRL_DOWN_MASK) != 0;
176 alt = (modifiers & (InputEvent.ALT_DOWN_MASK | InputEvent.ALT_GRAPH_DOWN_MASK)) != 0;
177 shift = (modifiers & InputEvent.SHIFT_DOWN_MASK) != 0;
178 meta = (modifiers & InputEvent.META_DOWN_MASK) != 0;
179 platformMenuShortcutKeyMask = (modifiers & PlatformManager.getPlatform().getMenuShortcutKeyMaskEx()) != 0;
180 }
181
182 /**
183 * Map old (pre jdk 1.4) modifiers to extended modifiers (only for Ctrl, Alt, Shift).
184 * @param modifiers old modifiers
185 * @return extended modifiers
186 */
187 private static int mapOldModifiers(int modifiers) {
188 if ((modifiers & InputEvent.CTRL_MASK) != 0) {
189 modifiers |= InputEvent.CTRL_DOWN_MASK;
190 }
191 if ((modifiers & InputEvent.META_MASK) != 0) {
192 modifiers |= InputEvent.META_DOWN_MASK;
193 }
194 if ((modifiers & InputEvent.ALT_MASK) != 0) {
195 modifiers |= InputEvent.ALT_DOWN_MASK;
196 }
197 if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
198 modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
199 }
200 if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
201 modifiers |= InputEvent.SHIFT_DOWN_MASK;
202 }
203
204 return modifiers;
205 }
206
207 protected void requestFocusInMapView() {
208 if (isEnabled()) {
209 // request focus in order to enable the expected keyboard shortcuts (see #8710)
210 MainApplication.getMap().mapView.requestFocus();
211 }
212 }
213
214 @Override
215 public void mouseReleased(MouseEvent e) {
216 requestFocusInMapView();
217 }
218
219 @Override
220 public void mouseExited(MouseEvent e) {
221 // Do nothing
222 }
223
224 @Override
225 public void mousePressed(MouseEvent e) {
226 requestFocusInMapView();
227 }
228
229 @Override
230 public void mouseClicked(MouseEvent e) {
231 // Do nothing
232 }
233
234 @Override
235 public void mouseEntered(MouseEvent e) {
236 // Do nothing
237 }
238
239 @Override
240 public void mouseMoved(MouseEvent e) {
241 // Do nothing
242 }
243
244 @Override
245 public void mouseDragged(MouseEvent e) {
246 // Do nothing
247 }
248
249 @Override
250 public void preferenceChanged(PreferenceChangeEvent e) {
251 readPreferences();
252 }
253
254 /**
255 * Determines if the given layer is a data layer that can be modified.
256 * Useful for {@link #layerIsSupported(Layer)} implementations.
257 * @param l layer
258 * @return {@code true} if the given layer is a data layer that can be modified
259 * @since 13434
260 */
261 protected boolean isEditableDataLayer(Layer l) {
262 return l instanceof OsmDataLayer && !((OsmDataLayer) l).isLocked();
263 }
264}
Note: See TracBrowser for help on using the repository browser.