Index: trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/actions/JoinAreasAction.java	(revision 11240)
@@ -43,4 +43,5 @@
 import org.openstreetmap.josm.gui.Notification;
 import org.openstreetmap.josm.gui.conflict.tags.CombinePrimitiveResolverDialog;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.tools.Geometry;
 import org.openstreetmap.josm.tools.Pair;
@@ -541,5 +542,5 @@
      * @throws UserCancelException if user cancels the operation
      */
-    private JoinAreasResult joinAreas(List<Multipolygon> areas) throws UserCancelException {
+    public JoinAreasResult joinAreas(List<Multipolygon> areas) throws UserCancelException {
 
         JoinAreasResult result = new JoinAreasResult();
@@ -1296,5 +1297,5 @@
      * @return list of polygons, or null if too complex relation encountered.
      */
-    private static List<Multipolygon> collectMultipolygons(Collection<Way> selectedWays) {
+    public static List<Multipolygon> collectMultipolygons(Collection<Way> selectedWays) {
 
         List<Multipolygon> result = new ArrayList<>();
@@ -1404,4 +1405,5 @@
     private RelationRole addOwnMultipolygonRelation(Collection<Way> inner) {
         if (inner.isEmpty()) return null;
+        OsmDataLayer layer = Main.getLayerManager().getEditLayer();
         // Create new multipolygon relation and add all inner ways to it
         Relation newRel = new Relation();
@@ -1410,5 +1412,6 @@
             newRel.addMember(new RelationMember("inner", w));
         }
-        cmds.add(new AddCommand(newRel));
+        cmds.add(layer != null ? new AddCommand(layer, newRel) :
+            new AddCommand(inner.iterator().next().getDataSet(), newRel));
         addedRelations.add(newRel);
 
@@ -1426,5 +1429,5 @@
         List<RelationRole> result = new ArrayList<>();
 
-        for (Relation r : Main.getLayerManager().getEditDataSet().getRelations()) {
+        for (Relation r : osm.getDataSet().getRelations()) {
             if (r.isDeleted()) {
                 continue;
@@ -1480,4 +1483,5 @@
         }
 
+        OsmDataLayer layer = Main.getLayerManager().getEditLayer();
         Relation newRel;
         switch (multiouters.size()) {
@@ -1508,5 +1512,5 @@
             }
             newRel.addMember(new RelationMember("outer", outer));
-            cmds.add(new AddCommand(newRel));
+            cmds.add(layer != null ? new AddCommand(layer, newRel) : new AddCommand(outer.getDataSet(), newRel));
         }
     }
Index: trunk/src/org/openstreetmap/josm/actions/PurgeAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/PurgeAction.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/actions/PurgeAction.java	(revision 11240)
@@ -93,5 +93,14 @@
             return;
 
-        Collection<OsmPrimitive> sel = getLayerManager().getEditDataSet().getAllSelected();
+        doPurge(getLayerManager().getEditDataSet().getAllSelected(), true);
+    }
+
+    /**
+     * Performs purge on selected OSM primitives.
+     * @param sel selected OSM primitives
+     * @param confirm asks user confirmation through a popup dialog
+     * @since 11240
+     */
+    public void doPurge(Collection<OsmPrimitive> sel, boolean confirm) {
         layer = Main.getLayerManager().getEditLayer();
 
@@ -205,5 +214,5 @@
         boolean clearUndoRedo = false;
 
-        if (!GraphicsEnvironment.isHeadless()) {
+        if (!GraphicsEnvironment.isHeadless() && confirm) {
             final boolean answer = ConditionalOptionPaneUtil.showConfirmationDialog(
                     "purge", Main.parent, buildPanel(modified), tr("Confirm Purging"),
@@ -216,5 +225,6 @@
         }
 
-        Main.main.undoRedo.add(new PurgeCommand(Main.getLayerManager().getEditLayer(), toPurgeChecked, makeIncomplete));
+        Main.main.undoRedo.add(layer != null ? new PurgeCommand(layer, toPurgeChecked, makeIncomplete) :
+            new PurgeCommand(toPurgeChecked.iterator().next().getDataSet(), toPurgeChecked, makeIncomplete));
 
         if (clearUndoRedo) {
Index: trunk/src/org/openstreetmap/josm/actions/SelectByInternalPointAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SelectByInternalPointAction.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/actions/SelectByInternalPointAction.java	(revision 11240)
@@ -30,6 +30,5 @@
 
     /**
-     * Returns the surrounding polygons/multipolygons
-     * ordered by their area size (from small to large)
+     * Returns the surrounding polygons/multipolygons ordered by their area size (from small to large)
      * which contain the internal point.
      *
@@ -38,5 +37,17 @@
      */
     public static Collection<OsmPrimitive> getSurroundingObjects(EastNorth internalPoint) {
-        final DataSet ds = Main.getLayerManager().getEditDataSet();
+        return getSurroundingObjects(Main.getLayerManager().getEditDataSet(), internalPoint);
+    }
+
+    /**
+     * Returns the surrounding polygons/multipolygons ordered by their area size (from small to large)
+     * which contain the internal point.
+     *
+     * @param ds the data set
+     * @param internalPoint the internal point.
+     * @return the surrounding polygons/multipolygons
+     * @since 11240
+     */
+    public static Collection<OsmPrimitive> getSurroundingObjects(DataSet ds, EastNorth internalPoint) {
         if (ds == null) {
             return Collections.emptySet();
Index: trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 11240)
@@ -539,5 +539,5 @@
         final Way changedWay = new Way(way);
         changedWay.setNodes(wayToKeep.getNodes());
-        commandList.add(new ChangeCommand(way, changedWay));
+        commandList.add(layer != null ? new ChangeCommand(layer, way, changedWay) : new ChangeCommand(way.getDataSet(), way, changedWay));
         if (!newSelection.contains(way)) {
             newSelection.add(way);
@@ -548,5 +548,5 @@
         newSelection.addAll(newWays);
         for (Way wayToAdd : newWays) {
-            commandList.add(new AddCommand(layer, wayToAdd));
+            commandList.add(layer != null ? new AddCommand(layer, wayToAdd) : new AddCommand(way.getDataSet(), wayToAdd));
         }
 
@@ -678,5 +678,5 @@
 
             if (c != null) {
-                commandList.add(new ChangeCommand(layer, r, c));
+                commandList.add(layer != null ? new ChangeCommand(layer, r, c) : new ChangeCommand(r.getDataSet(), r, c));
             }
         }
Index: trunk/src/org/openstreetmap/josm/command/AddCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/AddCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/AddCommand.java	(revision 11240)
@@ -11,4 +11,5 @@
 import javax.swing.Icon;
 
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
@@ -47,4 +48,15 @@
     public AddCommand(OsmDataLayer layer, OsmPrimitive osm) {
         super(layer);
+        this.osm = Objects.requireNonNull(osm, "osm");
+    }
+
+    /**
+     * Creates the command and specify the element to add in the context of the given data set.
+     * @param data The data set. Must not be {@code null}
+     * @param osm The primitive to add
+     * @since 11240
+     */
+    public AddCommand(DataSet data, OsmPrimitive osm) {
+        super(data);
         this.osm = Objects.requireNonNull(osm, "osm");
     }
Index: trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/AddPrimitivesCommand.java	(revision 11240)
@@ -106,10 +106,10 @@
             // a subsequent command (e.g. MoveCommand) cannot be redone.
             for (OsmPrimitive osm : createdPrimitives) {
-                getLayer().data.addPrimitive(osm);
+                getAffectedDataSet().addPrimitive(osm);
             }
             primitivesToSelect = createdPrimitivesToSelect;
         }
 
-        getLayer().data.setSelected(primitivesToSelect);
+        getAffectedDataSet().setSelected(primitivesToSelect);
         return true;
     }
Index: trunk/src/org/openstreetmap/josm/command/ChangeCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/ChangeCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/ChangeCommand.java	(revision 11240)
@@ -10,4 +10,5 @@
 import javax.swing.Icon;
 
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
@@ -47,4 +48,18 @@
     public ChangeCommand(OsmDataLayer layer, OsmPrimitive osm, OsmPrimitive newOsm) {
         super(layer);
+        this.osm = osm;
+        this.newOsm = newOsm;
+        sanityChecks();
+    }
+
+    /**
+     * Constructs a new {@code ChangeCommand} in the context of a given data set.
+     * @param data The data set
+     * @param osm The existing primitive to modify
+     * @param newOsm The new primitive
+     * @since 11240
+     */
+    public ChangeCommand(DataSet data, OsmPrimitive osm, OsmPrimitive newOsm) {
+        super(data);
         this.osm = osm;
         this.newOsm = newOsm;
Index: trunk/src/org/openstreetmap/josm/command/Command.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/Command.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/Command.java	(revision 11240)
@@ -137,4 +137,7 @@
     private final OsmDataLayer layer;
 
+    /** the dataset which this command is applied to */
+    private final DataSet data;
+
     /**
      * Creates a new command in the context of the current edit layer, if any
@@ -142,4 +145,5 @@
     public Command() {
         this.layer = Main.getLayerManager().getEditLayer();
+        this.data = layer != null ? layer.data : null;
     }
 
@@ -153,4 +157,18 @@
         CheckParameterUtil.ensureParameterNotNull(layer, "layer");
         this.layer = layer;
+        this.data = layer.data;
+    }
+
+    /**
+     * Creates a new command in the context of a specific data set, without data layer
+     *
+     * @param data the data set. Must not be null.
+     * @throws IllegalArgumentException if data is null
+     * @since 11240
+     */
+    public Command(DataSet data) {
+        CheckParameterUtil.ensureParameterNotNull(data, "data");
+        this.layer = null;
+        this.data = data;
     }
 
@@ -226,5 +244,5 @@
      */
     public DataSet getAffectedDataSet() {
-        return layer == null ? null : layer.data;
+        return data;
     }
 
@@ -331,5 +349,6 @@
         Command command = (Command) obj;
         return Objects.equals(cloneMap, command.cloneMap) &&
-                Objects.equals(layer, command.layer);
+               Objects.equals(layer, command.layer) &&
+               Objects.equals(data, command.data);
     }
 
Index: trunk/src/org/openstreetmap/josm/command/DeleteCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/DeleteCommand.java	(revision 11240)
@@ -29,4 +29,5 @@
 import org.openstreetmap.josm.actions.SplitWayAction;
 import org.openstreetmap.josm.actions.SplitWayAction.SplitWayResult;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
@@ -131,4 +132,21 @@
     public DeleteCommand(OsmDataLayer layer, Collection<? extends OsmPrimitive> data) {
         super(layer);
+        CheckParameterUtil.ensureParameterNotNull(data, "data");
+        this.toDelete = data;
+        checkConsistency();
+    }
+
+    /**
+     * Constructor for a collection of data to be deleted in the context of
+     * a specific data set
+     *
+     * @param dataset the dataset context for deleting these primitives. Must not be null.
+     * @param data the primitives to delete. Must neither be null nor empty.
+     * @throws IllegalArgumentException if dataset is null
+     * @throws IllegalArgumentException if data is null or empty
+     * @since 11240
+     */
+    public DeleteCommand(DataSet dataset, Collection<? extends OsmPrimitive> data) {
+        super(dataset);
         CheckParameterUtil.ensureParameterNotNull(data, "data");
         this.toDelete = data;
@@ -448,5 +466,6 @@
         //
         if (!primitivesToDelete.isEmpty()) {
-            cmds.add(new DeleteCommand(layer, primitivesToDelete));
+            cmds.add(layer != null ? new DeleteCommand(layer, primitivesToDelete) :
+                new DeleteCommand(primitivesToDelete.iterator().next().getDataSet(), primitivesToDelete));
         }
 
Index: trunk/src/org/openstreetmap/josm/command/PurgeCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/PurgeCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/PurgeCommand.java	(revision 11240)
@@ -43,13 +43,10 @@
     protected final ConflictCollection purgedConflicts = new ConflictCollection();
 
-    protected final DataSet ds;
-
     /**
+     * Constructs a new {@code PurgeCommand} (handles conflicts).
      * This command relies on a number of consistency conditions:
      *  - makeIncomplete must be a subset of toPurge.
-     *  - Each primitive, that is in toPurge but not in makeIncomplete, must
-     *      have all its referrers in toPurge.
-     *  - Each element of makeIncomplete must not be new and must have only
-     *      referrers that are either a relation or included in toPurge.
+     *  - Each primitive, that is in toPurge but not in makeIncomplete, must have all its referrers in toPurge.
+     *  - Each element of makeIncomplete must not be new and must have only referrers that are either a relation or included in toPurge.
      * @param layer OSM data layer
      * @param toPurge primitives to purge
@@ -58,5 +55,24 @@
     public PurgeCommand(OsmDataLayer layer, Collection<OsmPrimitive> toPurge, Collection<OsmPrimitive> makeIncomplete) {
         super(layer);
-        this.ds = layer.data;
+        init(toPurge, makeIncomplete);
+    }
+
+    /**
+     * Constructs a new {@code PurgeCommand} (does not handle conflicts).
+     * This command relies on a number of consistency conditions:
+     *  - makeIncomplete must be a subset of toPurge.
+     *  - Each primitive, that is in toPurge but not in makeIncomplete, must have all its referrers in toPurge.
+     *  - Each element of makeIncomplete must not be new and must have only referrers that are either a relation or included in toPurge.
+     * @param data OSM data set
+     * @param toPurge primitives to purge
+     * @param makeIncomplete primitives to make incomplete
+     * @since 11240
+     */
+    public PurgeCommand(DataSet data, Collection<OsmPrimitive> toPurge, Collection<OsmPrimitive> makeIncomplete) {
+        super(data);
+        init(toPurge, makeIncomplete);
+    }
+
+    private void init(Collection<OsmPrimitive> toPurge, Collection<OsmPrimitive> makeIncomplete) {
         /**
          * The topological sort is to avoid missing way nodes and missing
@@ -82,5 +98,5 @@
     @Override
     public boolean executeCommand() {
-        ds.beginUpdate();
+        getAffectedDataSet().beginUpdate();
         try {
             purgedConflicts.get().clear();
@@ -105,14 +121,16 @@
                     osm.load(empty);
                 } else {
-                    ds.removePrimitive(osm);
-                    Conflict<?> conflict = getLayer().getConflicts().getConflictForMy(osm);
-                    if (conflict != null) {
-                        purgedConflicts.add(conflict);
-                        getLayer().getConflicts().remove(conflict);
+                    getAffectedDataSet().removePrimitive(osm);
+                    if (getLayer() != null) {
+                        Conflict<?> conflict = getLayer().getConflicts().getConflictForMy(osm);
+                        if (conflict != null) {
+                            purgedConflicts.add(conflict);
+                            getLayer().getConflicts().remove(conflict);
+                        }
                     }
                 }
             }
         } finally {
-            ds.endUpdate();
+            getAffectedDataSet().endUpdate();
         }
         return true;
@@ -121,5 +139,5 @@
     @Override
     public void undoCommand() {
-        if (ds == null)
+        if (getAffectedDataSet() == null)
             return;
 
@@ -127,12 +145,12 @@
             PrimitiveData data = makeIncompleteDataByPrimId.get(osm);
             if (data != null) {
-                if (ds.getPrimitiveById(osm) != osm)
+                if (getAffectedDataSet().getPrimitiveById(osm) != osm)
                     throw new AssertionError(
                             String.format("Primitive %s has been made incomplete when purging, but it cannot be found on undo.", osm));
                 osm.load(data);
             } else {
-                if (ds.getPrimitiveById(osm) != null)
+                if (getAffectedDataSet().getPrimitiveById(osm) != null)
                     throw new AssertionError(String.format("Primitive %s was removed when purging, but is still there on undo", osm));
-                ds.addPrimitive(osm);
+                getAffectedDataSet().addPrimitive(osm);
             }
         }
@@ -279,5 +297,5 @@
     @Override
     public int hashCode() {
-        return Objects.hash(super.hashCode(), toPurge, makeIncompleteData, makeIncompleteDataByPrimId, purgedConflicts, ds);
+        return Objects.hash(super.hashCode(), toPurge, makeIncompleteData, makeIncompleteDataByPrimId, purgedConflicts, getAffectedDataSet());
     }
 
@@ -291,6 +309,5 @@
                 Objects.equals(makeIncompleteData, that.makeIncompleteData) &&
                 Objects.equals(makeIncompleteDataByPrimId, that.makeIncompleteDataByPrimId) &&
-                Objects.equals(purgedConflicts, that.purgedConflicts) &&
-                Objects.equals(ds, that.ds);
+                Objects.equals(purgedConflicts, that.purgedConflicts);
     }
 }
Index: trunk/src/org/openstreetmap/josm/command/conflict/DeletedStateConflictResolveCommand.java
===================================================================
--- trunk/src/org/openstreetmap/josm/command/conflict/DeletedStateConflictResolveCommand.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/command/conflict/DeletedStateConflictResolveCommand.java	(revision 11240)
@@ -74,5 +74,5 @@
 
     private void deleteMy() {
-        Set<OsmPrimitive> referrers = getLayer().data.unlinkReferencesToPrimitive(conflict.getMy());
+        Set<OsmPrimitive> referrers = getAffectedDataSet().unlinkReferencesToPrimitive(conflict.getMy());
         for (OsmPrimitive p : referrers) {
             if (!p.isNew() && !p.isDeleted()) {
Index: trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 11237)
+++ trunk/src/org/openstreetmap/josm/data/UndoRedoHandler.java	(revision 11240)
@@ -107,6 +107,9 @@
             return;
         DataSet ds = Main.getLayerManager().getEditDataSet();
-        Collection<? extends OsmPrimitive> oldSelection = ds.getSelected();
-        ds.beginUpdate();
+        Collection<? extends OsmPrimitive> oldSelection = null;
+        if (ds != null) {
+            oldSelection = ds.getSelected();
+            ds.beginUpdate();
+        }
         try {
             for (int i = 1; i <= num; ++i) {
@@ -120,8 +123,12 @@
             }
         } finally {
-            ds.endUpdate();
-        }
-        fireCommandsChanged();
-        fireIfSelectionChanged(ds, oldSelection);
+            if (ds != null) {
+                ds.endUpdate();
+            }
+        }
+        fireCommandsChanged();
+        if (ds != null) {
+            fireIfSelectionChanged(ds, oldSelection);
+        }
     }
 
