Index: trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 3503)
+++ trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 3504)
@@ -57,5 +57,5 @@
     }
 
-    protected boolean confirmChangeDirectionOfWays() {
+    protected static boolean confirmChangeDirectionOfWays() {
         ExtendedDialog ed = new ExtendedDialog(Main.parent,
                 tr("Change directions?"),
@@ -68,5 +68,5 @@
     }
 
-    protected void warnCombiningImpossible() {
+    protected static void warnCombiningImpossible() {
         String msg = tr("Could not combine ways "
                 + "(They could not be merged into a single string of nodes)");
@@ -80,5 +80,5 @@
     }
 
-    protected Way getTargetWay(Collection<Way> combinedWays) {
+    protected static Way getTargetWay(Collection<Way> combinedWays) {
         // init with an arbitrary way
         Way targetWay = combinedWays.iterator().next();
@@ -100,5 +100,5 @@
      * @return the set of referring relations
      */
-    protected Set<Relation> getParentRelations(Collection<Way> ways) {
+    public static Set<Relation> getParentRelations(Collection<Way> ways) {
         HashSet<Relation> ret = new HashSet<Relation>();
         for (Way w: ways) {
@@ -108,5 +108,22 @@
     }
 
-    public Way combineWays(Collection<Way> ways) {
+    @Deprecated
+    public static Way combineWays(Collection<Way> ways) {
+        Pair<Way, Command> combineResult;
+        try {
+            combineResult = combineWaysWorker(ways);
+        } catch (UserCancelException ex) {
+            return null;
+        }
+        return combineResult.a;
+    }
+
+    /**
+     * @param ways
+     * @return null if ways cannot be combined. Otherwise returns the combined
+     *              ways and the commands to combine
+     * @throws UserCancelException
+     */
+    public static Pair<Way, Command> combineWaysWorker(Collection<Way> ways) throws UserCancelException {
 
         // prepare and clean the list of ways to combine
@@ -170,10 +187,5 @@
                     Way wnew = new Way(w);
                     reversedTagWays.add(wnew);
-                    try {
-                        changePropertyCommands = reverseWayTagCorrector.execute(w, wnew);
-                    }
-                    catch(UserCancelException ex) {
-                        return null;
-                    }
+                    changePropertyCommands = reverseWayTagCorrector.execute(w, wnew);
                 }
                 if ((changePropertyCommands != null) && !changePropertyCommands.isEmpty()) {
@@ -214,5 +226,5 @@
             dialog.setVisible(true);
             if (dialog.isCancelled())
-                return null;
+                throw new UserCancelException();
         }
 
@@ -225,7 +237,6 @@
         cmds.add(new DeleteCommand(deletedWays));
         final SequenceCommand sequenceCommand = new SequenceCommand(tr("Combine {0} ways", ways.size()), cmds);
-        Main.main.undoRedo.add(sequenceCommand);
-
-        return targetWay;
+
+        return new Pair<Way, Command>(targetWay, sequenceCommand);
     }
 
@@ -245,5 +256,15 @@
         }
         // combine and update gui
-        final Way selectedWay = combineWays(selectedWays);
+        Pair<Way, Command> combineResult;
+        try {
+            combineResult = combineWaysWorker(selectedWays);
+        } catch (UserCancelException ex) {
+            return;
+        }
+
+        if (combineResult == null)
+            return;
+        final Way selectedWay = combineResult.a;
+        Main.main.undoRedo.add(combineResult.b);
         if(selectedWay != null)
         {
Index: trunk/src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 3503)
+++ trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 3504)
@@ -179,8 +179,7 @@
      * Override in subclasses to update the enabled state of the action if the
      * collection of selected primitives changes. This method is called with the
-     * new selection. Avoid calling getCurrentDataSet().getSelected() because this
-     * loops over the complete data set.
-     *
-     * @param selection the collection of selected primitives
+     * new selection.
+     *
+     * @param selection the collection of selected primitives; may be empty, but not null
      *
      * @see #updateEnabledState()
Index: trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 3503)
+++ trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 3504)
@@ -7,4 +7,5 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -24,11 +25,47 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.tools.Shortcut;
+import org.openstreetmap.josm.tools.Utils;
 
 public final class ReverseWayAction extends JosmAction {
+
+    public static class ReverseWayResult {
+        private Way newWay;
+        private Collection<Command> tagCorrectionCommands;
+        private Command reverseCommand;
+
+        public ReverseWayResult(Way newWay, Collection<Command> tagCorrectionCommands, Command reverseCommand) {
+            this.newWay = newWay;
+            this.tagCorrectionCommands = tagCorrectionCommands;
+            this.reverseCommand = reverseCommand;
+        }
+
+        public Way getNewWay() {
+            return newWay;
+        }
+
+        public Collection<Command> getCommands() {
+            List<Command> c = new ArrayList<Command>();
+            c.addAll(tagCorrectionCommands);
+            c.add(reverseCommand);
+            return c;
+        }
+
+        public Command getAsSequenceCommand() {
+            return new SequenceCommand(tr("Reverse way"), getCommands());
+        }
+
+        public Command getReverseCommand() {
+            return reverseCommand;
+        }
+
+        public Collection<Command> getTagCorrectionCommands() {
+            return tagCorrectionCommands;
+        }
+    }
 
     public ReverseWayAction() {
         super(tr("Reverse Ways"), "wayflip", tr("Reverse the direction of all selected ways."),
                 Shortcut.registerShortcut("tools:reverse", tr("Tool: {0}", tr("Reverse Ways")), KeyEvent.VK_R, Shortcut.GROUP_EDIT), true);
-        putValue("help", ht("/Action/ReverseWay"));
+        putValue("help", ht("/Action/ReverseWays"));
     }
 
@@ -51,25 +88,14 @@
 
         boolean propertiesUpdated = false;
-        ReverseWayTagCorrector reverseWayTagCorrector = new ReverseWayTagCorrector();
         Collection<Command> c = new LinkedList<Command>();
         for (Way w : sel) {
-            Way wnew = new Way(w);
-            List<Node> nodesCopy = wnew.getNodes();
-            Collections.reverse(nodesCopy);
-            wnew.setNodes(nodesCopy);
-            if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
-                try
-                {
-                    final Collection<Command> changePropertyCommands = reverseWayTagCorrector.execute(w, wnew);
-                    propertiesUpdated = propertiesUpdated
-                    || (changePropertyCommands != null && !changePropertyCommands.isEmpty());
-                    c.addAll(changePropertyCommands);
-                }
-                catch(UserCancelException ex)
-                {
-                    return;
-                }
+            ReverseWayResult revResult;
+            try {
+                revResult = reverseWay(w);
+            } catch (UserCancelException ex) {
+                return;
             }
-            c.add(new ChangeCommand(w, wnew));
+            c.addAll(revResult.getCommands());
+            propertiesUpdated |= !revResult.getTagCorrectionCommands().isEmpty();
         }
         Main.main.undoRedo.add(new SequenceCommand(tr("Reverse ways"), c));
@@ -78,4 +104,21 @@
         }
         Main.map.repaint();
+    }
+
+    /**
+     * @param w the way
+     * @return the reverse command and the tag correction commands
+     */
+    public static ReverseWayResult reverseWay(Way w) throws UserCancelException {
+        Way wnew = new Way(w);
+        List<Node> nodesCopy = wnew.getNodes();
+        Collections.reverse(nodesCopy);
+        wnew.setNodes(nodesCopy);
+
+        Collection<Command> corrCmds = Collections.<Command>emptyList();
+        if (Main.pref.getBoolean("tag-correction.reverse-way", true)) {
+            corrCmds = (new ReverseWayTagCorrector()).execute(w, wnew);
+        }
+        return new ReverseWayResult(wnew, corrCmds, new ChangeCommand(w, wnew));
     }
 
@@ -102,15 +145,5 @@
     @Override
     protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
-        if (selection == null) {
-            setEnabled(false);
-            return;
-        }
-        int n = 0;
-        for (OsmPrimitive primitive : selection) {
-            if (primitive instanceof Way) {
-                n++;
-            }
-        }
-        setEnabled(n > 0);
+        setEnabled(Utils.exists(selection, OsmPrimitive.wayPredicate));
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3503)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 3504)
@@ -346,5 +346,5 @@
     /**
      * Replies an unmodifiable collection of primitives currently selected
-     * in this dataset
+     * in this dataset. May be empty, but not null.
      *
      * @return unmodifiable collection of primitives
Index: trunk/src/org/openstreetmap/josm/data/osm/Storage.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Storage.java	(revision 3503)
+++ trunk/src/org/openstreetmap/josm/data/osm/Storage.java	(revision 3504)
@@ -132,4 +132,5 @@
      *          modify, but the read-only iteration will happen on a copy
      *          of the unmodified Storage.
+     *          This is similar to CopyOnWriteArrayList.
      */
     public Storage(Hash<? super T, ? super T> ha, int capacity, boolean safeIterator) {
Index: trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 3504)
+++ trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 3504)
@@ -0,0 +1,13 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+public class Utils {
+
+    public static <T> boolean exists(Iterable<? extends T> coll, Predicate<? super T> pred) {
+        for (T el : coll) {
+            if (pred.evaluate(el))
+                return true;
+        }
+        return false;
+    }
+}
