Index: trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 2025)
+++ trunk/src/org/openstreetmap/josm/actions/mapmode/DeleteAction.java	(revision 2026)
@@ -4,15 +4,24 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.AWTEvent;
+import java.awt.Cursor;
+import java.awt.EventQueue;
+import java.awt.Toolkit;
+import java.awt.event.AWTEventListener;
 import java.awt.event.ActionEvent;
 import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseEvent;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.DeleteCommand;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.WaySegment;
 import org.openstreetmap.josm.gui.MapFrame;
@@ -38,5 +47,41 @@
  * @author imi
  */
-public class DeleteAction extends MapMode {
+
+/**
+ * This class contains stubs for highlighting affected primitives when affected.
+ * However, way segments can be deleted as well, but cannot be highlighted
+ * alone. If the highlight feature for this delete action is to be implemented
+ * properly, highlighting way segments must be possible first. --xeen, 2009-09-02
+ */
+public class DeleteAction extends MapMode implements AWTEventListener {
+    //private boolean drawTargetHighlight;
+    private boolean drawTargetCursor;
+    //private Collection<? extends OsmPrimitive> oldPrims = null;
+
+    // Cache previous mouse event (needed when only the modifier keys are
+    // pressed but the mouse isn't moved)
+    private MouseEvent oldEvent = null;
+
+    private enum Cursors {
+        none,
+        node,
+        segment,
+        way_node_only,
+        way_normal,
+        way_only;
+
+        private Cursor c = null;
+        // This loads and caches the cursor for each
+        public Cursor cursor() {
+            if(c == null) {
+                String nm = "delete_" + this.name().toLowerCase();
+                // "None" has no special icon
+                nm = nm.equals("delete_none") ? "delete" : nm;
+                this.c = ImageProvider.getCursor("normal", nm);
+            }
+            return c;
+        }
+    }
+    private Cursors currCursor = Cursors.none;
 
     /**
@@ -57,5 +102,15 @@
         if (!isEnabled())
             return;
+        //drawTargetHighlight = Main.pref.getBoolean("draw.target-highlight", true);
+        drawTargetCursor = Main.pref.getBoolean("draw.target-cursor", true);
+
         Main.map.mapView.addMouseListener(this);
+        Main.map.mapView.addMouseMotionListener(this);
+        // This is required to update the cursors when ctrl/shift/alt is pressed
+        try {
+            Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
+        } catch (SecurityException ex) {}
+
+        currCursor = Cursors.none;
     }
 
@@ -63,4 +118,8 @@
         super.exitMode();
         Main.map.mapView.removeMouseListener(this);
+        Main.map.mapView.removeMouseMotionListener(this);
+        try {
+            Toolkit.getDefaultToolkit().removeAWTEventListener(this);
+        } catch (SecurityException ex) {}
     }
 
@@ -94,4 +153,96 @@
 
     /**
+     * Listen to mouse move to be able to update the cursor (and highlights)
+     * @param MouseEvent The mouse event that has been captured
+     */
+    @Override public void mouseMoved(MouseEvent e) {
+        oldEvent = e;
+        updateCursor(e, e.getModifiers());
+    }
+
+    /**
+     * This function handles all work related to updating the cursor and
+     * highlights. For now, only the cursor is enabled because highlighting
+     * requires WaySegment to be highlightable.
+     * 
+     * Normally the mouse event also contains the modifiers. However, when the
+     * mouse is not moved and only modifier keys are pressed, no mouse event
+     * occurs. We can use AWTEvent to catch those but still lack a proper
+     * mouseevent. Instead we copy the previous event and only update the
+     * modifiers.
+     * 
+     * @param MouseEvent
+     * @parm int modifiers
+     */
+    private void updateCursor(MouseEvent e, int modifiers) {
+        if(!Main.map.mapView.isActiveLayerVisible() || e == null)
+            return;
+
+        // Clean old highlights
+        //cleanOldHighlights();
+
+        Command c = buildDeleteCommands(e, modifiers, true);
+        if(c == null) {
+            setCursor(Cursors.none);
+            return;
+        }
+
+        Collection<OsmPrimitive> prims = new HashSet<OsmPrimitive>();
+        Collection<OsmPrimitive> mods = new HashSet<OsmPrimitive>();
+        c.fillModifiedData(mods, prims, prims);
+
+        if(prims.size() == 0 && mods.size() == 0) {
+            // Default-Cursor
+            setCursor(Cursors.none);
+            return;
+        }
+
+        // There are no deleted parts if solely a way segment is deleted
+        // This is no the case when actually deleting only a segment but that
+        // segment happens to be the whole way. This is an acceptable error
+        // though
+        if(prims.size() == 0) {
+            setCursor(Cursors.segment);
+        } else if(prims.size() == 1 && prims.toArray()[0] instanceof Node) {
+            setCursor(Cursors.node);
+        } else if(prims.size() == 1 && prims.toArray()[0] instanceof Way) {
+            setCursor(Cursors.way_only);
+        } else {
+            // Decide between non-accel click where "useless" nodes are deleted
+            // and ctrl-click where nodes and ways are deleted
+            boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
+            if(ctrl) {
+                setCursor(Cursors.way_node_only);
+            } else {
+                setCursor(Cursors.way_normal);
+            }
+
+        }
+
+        // Needs to implement WaySegment highlight first
+        /*if(drawTargetHighlight) {
+            // Add new highlights
+            for(OsmPrimitive p : prims) {
+                p.highlighted = true;
+            }
+            oldPrims = prims;
+        }*/
+
+        // We only need to repaint if the highlights changed
+        //Main.map.mapView.repaint();
+    }
+
+    /**
+     * Small helper function that cleans old highlights
+     */
+    /*private void cleanOldHighlights() {
+        if(oldPrims == null)
+            return;
+        for(OsmPrimitive p: oldPrims) {
+            p.highlighted = false;
+        }
+    }*/
+
+    /**
      * If user clicked with the left button, delete the nearest object.
      * position.
@@ -107,7 +258,65 @@
         Main.map.mapView.requestFocus();
 
-        boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
-        boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
-        boolean alt = (e.getModifiers() & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
+        Command c = buildDeleteCommands(e, e.getModifiers(), false);
+        if (c != null) {
+            Main.main.undoRedo.add(c);
+        }
+
+        getCurrentDataSet().setSelected();
+        Main.map.mapView.repaint();
+    }
+
+    @Override public String getModeHelpText() {
+        return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
+    }
+
+    @Override public boolean layerIsSupported(Layer l) {
+        return l instanceof OsmDataLayer;
+    }
+
+    @Override
+    protected void updateEnabledState() {
+        setEnabled(Main.map != null && Main.map.mapView != null && Main.map.mapView.isActiveLayerDrawable());
+    }
+
+    /**
+     * Deletes the relation in the context of the given layer. Also notifies
+     * {@see RelationDialogManager} and {@see OsmDataLayer#fireDataChange()} events.
+     * 
+     * @param layer the layer in whose context the relation is deleted. Must not be null.
+     * @param toDelete  the relation to be deleted. Must  not be null.
+     * @exception IllegalArgumentException thrown if layer is null
+     * @exception IllegalArgumentException thrown if toDelete is nul
+     */
+    public static void deleteRelation(OsmDataLayer layer, Relation toDelete) {
+        if (layer == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "layer"));
+        if (toDelete == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "toDelete"));
+
+        Command cmd = DeleteCommand.delete(layer, Collections.singleton(toDelete));
+        if (cmd != null) {
+            // cmd can be null if the user cancels dialogs DialogCommand displays
+            Main.main.undoRedo.add(cmd);
+            RelationDialogManager.getRelationDialogManager().close(layer, toDelete);
+            layer.fireDataChange();
+        }
+    }
+
+    /**
+     * This function takes any mouse event argument and builds the list of elements
+     * that should be deleted but does not actually delete them.
+     * @param e MouseEvent from which modifiers and position are taken
+     * @param int modifiers For explanation: @see updateCursor
+     * @param Simulate Set to true if the user should be bugged with additional
+     *        dialogs
+     * @return
+     */
+    private Command buildDeleteCommands(MouseEvent e, int modifiers, boolean simulate) {
+        // Note: CTRL is the only modifier that is checked in MouseMove, don't
+        // forget updating it there
+        boolean ctrl = (modifiers & ActionEvent.CTRL_MASK) != 0;
+        boolean shift = (modifiers & ActionEvent.SHIFT_MASK) != 0;
+        boolean alt = (modifiers & (ActionEvent.ALT_MASK|InputEvent.ALT_GRAPH_MASK)) != 0;
 
         OsmPrimitive sel = Main.map.mapView.getNearestNode(e.getPoint());
@@ -119,7 +328,7 @@
                     c = DeleteCommand.deleteWaySegment(getEditLayer(),ws);
                 } else if (ctrl) {
-                    c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way));
+                    c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way),true);
                 } else {
-                    c = DeleteCommand.delete(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way), !alt);
+                    c = DeleteCommand.delete(getEditLayer(),Collections.singleton((OsmPrimitive)ws.way), !alt, simulate);
                 }
             }
@@ -127,51 +336,43 @@
             c = DeleteCommand.deleteWithReferences(getEditLayer(),Collections.singleton(sel));
         } else {
-            c = DeleteCommand.delete(getEditLayer(),Collections.singleton(sel), !alt);
-        }
-        if (c != null) {
-            Main.main.undoRedo.add(c);
-        }
-
-        getCurrentDataSet().setSelected();
-        Main.map.mapView.repaint();
-    }
-
-    @Override public String getModeHelpText() {
-        return tr("Click to delete. Shift: delete way segment. Alt: don't delete unused nodes when deleting a way. Ctrl: delete referring objects.");
-    }
-
-    @Override public boolean layerIsSupported(Layer l) {
-        return l instanceof OsmDataLayer;
-    }
-
-    @Override
-    protected void updateEnabledState() {
-        setEnabled(Main.map != null && Main.map.mapView != null && Main.map.mapView.isActiveLayerDrawable());
-    }
-
-    /**
-     * Deletes the relation in the context of the given layer. Also notifies
-     * {@see RelationDialogManager} and {@see OsmDataLayer#fireDataChange()} events.
-     * 
-     * @param layer the layer in whose context the relation is deleted. Must not be null.
-     * @param toDelete  the relation to be deleted. Must  not be null.
-     * @exception IllegalArgumentException thrown if layer is null
-     * @exception IllegalArgumentException thrown if toDelete is nul
-     */
-    public static void deleteRelation(OsmDataLayer layer, Relation toDelete) {
-        if (layer == null)
-            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "layer"));
-        if (toDelete == null)
-            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "toDelete"));
-        if (toDelete == null)
-            return;
-        Command cmd = DeleteCommand.delete(layer, Collections.singleton(toDelete));
-        if (cmd != null) {
-            // cmd can be null if the user cancels dialogs DialogCommand displays
-            //
-            Main.main.undoRedo.add(cmd);
-            RelationDialogManager.getRelationDialogManager().close(layer, toDelete);
-            layer.fireDataChange();
-        }
+            c = DeleteCommand.delete(getEditLayer(),Collections.singleton(sel), !alt, simulate);
+        }
+
+        return c;
+    }
+
+    /**
+     * This function sets the given cursor in a safe way. This implementation
+     * differs from the on in DrawAction (it is favorable, too).
+     * FIXME: Update DrawAction to use this "setCursor-style" and move function
+     * to MapMode.
+     * @param c
+     */
+    private void setCursor(final Cursors c) {
+        if(currCursor.equals(c) || (!drawTargetCursor && currCursor.equals(Cursors.none)))
+            return;
+        try {
+            // We invoke this to prevent strange things from happening
+            EventQueue.invokeLater(new Runnable() {
+                public void run() {
+                    // Don't change cursor when mode has changed already
+                    if(!(Main.map.mapMode instanceof DeleteAction))
+                        return;
+
+                    Main.map.mapView.setCursor(c.cursor());
+                    //System.out.println("Set cursor to: " + c.name());
+                }
+            });
+            currCursor = c;
+        } catch(Exception e) {}
+    }
+
+    /**
+     * This is required to update the cursors when ctrl/shift/alt is pressed
+     */
+    public void eventDispatched(AWTEvent e) {
+        // We don't have a mouse event, so we pass the old mouse event but the
+        // new modifiers.
+        updateCursor(oldEvent, ((InputEvent)e).getModifiers());
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 2025)
+++ trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 2026)
@@ -43,5 +43,4 @@
  */
 public class DeleteCommand extends Command {
-
     /**
      * The primitives that get deleted.
@@ -157,8 +156,10 @@
      * If a way is deleted, only the way and no nodes are deleted.
      *
+     * @param layer
      * @param selection The list of all object to be deleted.
+     * @param simulate  Set to true if the user should not be bugged with additional dialogs
      * @return command A command to perform the deletions, or null of there is nothing to delete.
      */
-    public static Command deleteWithReferences(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection) {
+    public static Command deleteWithReferences(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection, boolean simulate) {
         CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(layer.data);
         for (OsmPrimitive osm : selection) {
@@ -168,10 +169,19 @@
         if (v.data.isEmpty())
             return null;
-        if (!checkAndConfirmOutlyingDeletes(layer,v.data))
+        if (!checkAndConfirmOutlyingDeletes(layer,v.data) && !simulate)
             return null;
         return new DeleteCommand(layer,v.data);
     }
 
-    private static int testRelation(Relation ref, OsmPrimitive osm) {
+    public static Command deleteWithReferences(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection) {
+        return deleteWithReferences(layer, selection, false);
+    }
+
+    private static int testRelation(Relation ref, OsmPrimitive osm, boolean simulate) {
+        // If this delete action is simulated, do not bug the user with dialogs
+        // and assume the relations should be deleted
+        if(simulate)
+            return 1;
+
         String role = new String();
         for (RelationMember m : ref.getMembers()) {
@@ -195,5 +205,5 @@
 
     public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection) {
-        return delete(layer, selection, true);
+        return delete(layer, selection, true, false);
     }
 
@@ -243,7 +253,14 @@
      * @param selection The objects to delete.
      * @param alsoDeleteNodesInWay <code>true</code> if nodes should be deleted as well
+     * @param simulate Set to true if the user should not be bugged with additional questions
      * @return command a command to perform the deletions, or null if there is nothing to delete.
      */
-    public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection, boolean alsoDeleteNodesInWay) {
+    public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection,
+            boolean alsoDeleteNodesInWay) {
+        return delete(layer, selection, alsoDeleteNodesInWay, false);
+    }
+
+    public static Command delete(OsmDataLayer layer, Collection<? extends OsmPrimitive> selection,
+            boolean alsoDeleteNodesInWay, boolean simulate) {
         if (selection.isEmpty())
             return null;
@@ -260,5 +277,5 @@
         }
 
-        if (!checkAndConfirmOutlyingDeletes(layer,primitivesToDelete))
+        if (!checkAndConfirmOutlyingDeletes(layer,primitivesToDelete) && !simulate)
             return null;
 
@@ -273,5 +290,5 @@
                     waysToBeChanged.add((Way) ref);
                 } else if (ref instanceof Relation) {
-                    if (testRelation((Relation) ref, osm) == 1) {
+                    if (testRelation((Relation) ref, osm, simulate) == 1) {
                         Collection<OsmPrimitive> relset = relationsToBeChanged.get(ref);
                         if (relset == null) {
@@ -314,5 +331,5 @@
                         }
                         if (!found) {
-                            if (testRelation((Relation) ref, w) == 1) {
+                            if (testRelation((Relation) ref, w, simulate) == 1) {
                                 relset.add(w);
                                 relationsToBeChanged.put(ref, relset);
