| 40 | | public class DeleteAction extends MapMode { |
| | 49 | |
| | 50 | /** |
| | 51 | * This class contains stubs for highlighting affected primitives when affected. |
| | 52 | * However, way segments can be deleted as well, but cannot be highlighted |
| | 53 | * alone. If the highlight feature for this delete action is to be implemented |
| | 54 | * properly, highlighting way segments must be possible first. --xeen, 2009-09-02 |
| | 55 | */ |
| | 56 | public class DeleteAction extends MapMode implements AWTEventListener { |
| | 57 | //private boolean drawTargetHighlight; |
| | 58 | private boolean drawTargetCursor; |
| | 59 | //private Collection<? extends OsmPrimitive> oldPrims = null; |
| | 60 | |
| | 61 | // Cache previous mouse event (needed when only the modifier keys are |
| | 62 | // pressed but the mouse isn't moved) |
| | 63 | private MouseEvent oldEvent = null; |
| | 64 | |
| | 65 | private enum Cursors { |
| | 66 | none, |
| | 67 | node, |
| | 68 | segment, |
| | 69 | way_node_only, |
| | 70 | way_normal, |
| | 71 | way_only; |
| | 72 | |
| | 73 | private Cursor c = null; |
| | 74 | // This loads and caches the cursor for each |
| | 75 | public Cursor cursor() { |
| | 76 | if(c == null) { |
| | 77 | String nm = "delete_" + this.name().toLowerCase(); |
| | 78 | // "None" has no special icon |
| | 79 | nm = nm.equals("delete_none") ? "delete" : nm; |
| | 80 | this.c = ImageProvider.getCursor("normal", nm); |
| | 81 | } |
| | 82 | return c; |
| | 83 | } |
| | 84 | } |
| | 85 | private Cursors currCursor = Cursors.none; |
| | 155 | * Listen to mouse move to be able to update the cursor (and highlights) |
| | 156 | * @param MouseEvent The mouse event that has been captured |
| | 157 | */ |
| | 158 | @Override public void mouseMoved(MouseEvent e) { |
| | 159 | oldEvent = e; |
| | 160 | updateCursor(e, e.getModifiers()); |
| | 161 | } |
| | 162 | |
| | 163 | /** |
| | 164 | * This function handles all work related to updating the cursor and |
| | 165 | * highlights. For now, only the cursor is enabled because highlighting |
| | 166 | * requires WaySegment to be highlightable. |
| | 167 | * |
| | 168 | * Normally the mouse event also contains the modifiers. However, when the |
| | 169 | * mouse is not moved and only modifier keys are pressed, no mouse event |
| | 170 | * occurs. We can use AWTEvent to catch those but still lack a proper |
| | 171 | * mouseevent. Instead we copy the previous event and only update the |
| | 172 | * modifiers. |
| | 173 | * |
| | 174 | * @param MouseEvent |
| | 175 | * @parm int modifiers |
| | 176 | */ |
| | 177 | private void updateCursor(MouseEvent e, int modifiers) { |
| | 178 | if(!Main.map.mapView.isActiveLayerVisible() || e == null) |
| | 179 | return; |
| | 180 | |
| | 181 | // Clean old highlights |
| | 182 | //cleanOldHighlights(); |
| | 183 | |
| | 184 | Command c = buildDeleteCommands(e, modifiers, true); |
| | 185 | if(c == null) { |
| | 186 | setCursor(Cursors.none); |
| | 187 | return; |
| | 188 | } |
| | 189 | |
| | 190 | Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>(); |
| | 191 | Collection<OsmPrimitive> mods = new HashSet<OsmPrimitive>(); |
| | 192 | c.fillModifiedData(mods, prims, prims); |
| | 193 | |
| | 194 | if(prims.size() == 0 && mods.size() == 0) { |
| | 195 | // Default-Cursor |
| | 196 | setCursor(Cursors.none); |
| | 197 | return; |
| | 198 | } |
| | 199 | |
| | 200 | // There are no deleted parts if solely a way segment is deleted |
| | 201 | // This is no the case when actually deleting only a segment but that |
| | 202 | // segment happens to be the whole way. This is an acceptable error |
| | 203 | // though |
| | 204 | if(prims.size() == 0) { |
| | 205 | setCursor(Cursors.segment); |
| | 206 | } else if(prims.size() == 1 && prims.toArray()[0] instanceof Node) { |
| | 207 | setCursor(Cursors.node); |
| | 208 | } else if(prims.size() == 1 && prims.toArray()[0] instanceof Way) { |
| | 209 | setCursor(Cursors.way_only); |
| | 210 | } else { |
| | 211 | // Decide between non-accel click where "useless" nodes are deleted |
| | 212 | // and ctrl-click where nodes and ways are deleted |
| | 213 | boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0; |
| | 214 | if(ctrl) { |
| | 215 | setCursor(Cursors.way_node_only); |
| | 216 | } else { |
| | 217 | setCursor(Cursors.way_normal); |
| | 218 | } |
| | 219 | |
| | 220 | } |
| | 221 | |
| | 222 | // Needs to implement WaySegment highlight first |
| | 223 | /*if(drawTargetHighlight) { |
| | 224 | // Add new highlights |
| | 225 | for(OsmPrimitive p : prims) { |
| | 226 | p.highlighted = true; |
| | 227 | } |
| | 228 | oldPrims = prims; |
| | 229 | }*/ |
| | 230 | |
| | 231 | // We only need to repaint if the highlights changed |
| | 232 | //Main.map.mapView.repaint(); |
| | 233 | } |
| | 234 | |
| | 235 | /** |
| | 236 | * Small helper function that cleans old highlights |
| | 237 | */ |
| | 238 | /*private void cleanOldHighlights() { |
| | 239 | if(oldPrims == null) |
| | 240 | return; |
| | 241 | for(OsmPrimitive p: oldPrims) { |
| | 242 | p.highlighted = false; |
| | 243 | } |
| | 244 | }*/ |
| | 245 | |
| | 246 | /** |
| 109 | | boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0; |
| 110 | | boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0; |
| 111 | | boolean alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0; |
| 112 | | |
| 113 | | OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint()); |
| 114 | | Command c = null; |
| 115 | | if (sel == null) { |
| 116 | | WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint()); |
| 117 | | if (ws != null) { |
| 118 | | if (shift) { |
| 119 | | c = DeleteCommand.deleteWaySegment(getEditLayer(),ws); |
| 120 | | } else if (ctrl) { |
| 121 | | c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way)); |
| 122 | | } else { |
| 123 | | c = DeleteCommand.delete(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way), !alt); |
| 124 | | } |
| 125 | | } |
| 126 | | } else if (ctrl) { |
| 127 | | c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(sel)); |
| 128 | | } else { |
| 129 | | c = DeleteCommand.delete(getEditLayer(),Collections.singleton(sel), !alt); |
| 130 | | } |
| | 260 | Command c = buildDeleteCommands(e, e.getModifiers(), false); |
| | 305 | |
| | 306 | /** |
| | 307 | * This function takes any mouse event argument and builds the list of elements |
| | 308 | * that should be deleted but does not actually delete them. |
| | 309 | * @param e MouseEvent from which modifiers and position are taken |
| | 310 | * @param int modifiers For explanation: @see updateCursor |
| | 311 | * @param Simulate Set to true if the user should be bugged with additional |
| | 312 | * dialogs |
| | 313 | * @return |
| | 314 | */ |
| | 315 | private Command buildDeleteCommands(MouseEvent e, int modifiers, boolean simulate) { |
| | 316 | // Note: CTRL is the only modifier that is checked in MouseMove, don't |
| | 317 | // forget updating it there |
| | 318 | boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0; |
| | 319 | boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0; |
| | 320 | boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0; |
| | 321 | |
| | 322 | OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint()); |
| | 323 | Command c = null; |
| | 324 | if (sel == null) { |
| | 325 | WaySegment ws = Main.map.mapView.getNearestWaySegment(e.getPoint()); |
| | 326 | if (ws != null) { |
| | 327 | if (shift) { |
| | 328 | c = DeleteCommand.deleteWaySegment(getEditLayer(),ws); |
| | 329 | } else if (ctrl) { |
| | 330 | c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way),true); |
| | 331 | } else { |
| | 332 | c = DeleteCommand.delete(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way), !alt, simulate); |
| | 333 | } |
| | 334 | } |
| | 335 | } else if (ctrl) { |
| | 336 | c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(sel)); |
| | 337 | } else { |
| | 338 | c = DeleteCommand.delete(getEditLayer(),Collections.singleton(sel), !alt, simulate); |
| | 339 | } |
| | 340 | |
| | 341 | return c; |
| | 342 | } |
| | 343 | |
| | 344 | /** |
| | 345 | * This function sets the given cursor in a safe way. This implementation |
| | 346 | * differs from the on in DrawAction (it is favorable, too). |
| | 347 | * FIXME: Update DrawAction to use this "setCursor-style" and move function |
| | 348 | * to MapMode. |
| | 349 | * @param c |
| | 350 | */ |
| | 351 | private void setCursor(final Cursors c) { |
| | 352 | if(currCursor.equals(c) || (!drawTargetCursor && currCursor.equals(Cursors.none))) |
| | 353 | return; |
| | 354 | try { |
| | 355 | // We invoke this to prevent strange things from happening |
| | 356 | EventQueue.invokeLater(new Runnable() { |
| | 357 | public void run() { |
| | 358 | // Don't change cursor when mode has changed already |
| | 359 | if(!(Main.map.mapMode instanceof DeleteAction)) |
| | 360 | return; |
| | 361 | |
| | 362 | Main.map.mapView.setCursor(c.cursor()); |
| | 363 | //System.out.println("Set cursor to: " + c.name()); |
| | 364 | } |
| | 365 | }); |
| | 366 | currCursor = c; |
| | 367 | } catch(Exception e) {} |
| | 368 | } |
| | 369 | |
| | 370 | /** |
| | 371 | * This is required to update the cursors when ctrl/shift/alt is pressed |
| | 372 | */ |
| | 373 | public void eventDispatched(AWTEvent e) { |
| | 374 | // We don't have a mouse event, so we pass the old mouse event but the |
| | 375 | // new modifiers. |
| | 376 | updateCursor(oldEvent, ((InputEvent)e).getModifiers()); |
| | 377 | } |