Index: trunk/src/org/openstreetmap/josm/actions/AbstractUploadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/AbstractUploadAction.java	(revision 15513)
+++ trunk/src/org/openstreetmap/josm/actions/AbstractUploadAction.java	(revision 15513)
@@ -0,0 +1,62 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import java.beans.PropertyChangeListener;
+
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
+import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Abstract super-class of all upload actions.
+ * Listens to layer change events to update its enabled state.
+ * @since xxx
+ */
+public abstract class AbstractUploadAction extends JosmAction {
+
+    /**
+     * Constructs a new {@code AbstractUploadAction}.
+     *
+     * @param name the action's text as displayed on the menu (if it is added to a menu)
+     * @param iconName the filename of the icon to use
+     * @param tooltip  a longer description of the action that will be displayed in the tooltip. Please note
+     *           that html is not supported for menu actions on some platforms.
+     * @param shortcut a ready-created shortcut object or null if you don't want a shortcut. But you always
+     *            do want a shortcut, remember you can always register it with group=none, so you
+     *            won't be assigned a shortcut unless the user configures one. If you pass null here,
+     *            the user CANNOT configure a shortcut for your action.
+     * @param registerInToolbar register this action for the toolbar preferences?
+     */
+    public AbstractUploadAction(String name, String iconName, String tooltip, Shortcut shortcut,
+            boolean registerInToolbar) {
+        super(name, iconName, tooltip, shortcut, registerInToolbar);
+    }
+
+    private final PropertyChangeListener updateOnRequireUploadChange = evt -> {
+        if (OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP.equals(evt.getPropertyName())) {
+            updateEnabledState();
+        }
+    };
+
+    @Override
+    protected LayerChangeAdapter buildLayerChangeAdapter() {
+        return new LayerChangeAdapter() {
+            @Override
+            public void layerAdded(LayerAddEvent e) {
+                if (e.getAddedLayer() instanceof OsmDataLayer) {
+                    e.getAddedLayer().addPropertyChangeListener(updateOnRequireUploadChange);
+                }
+                super.layerAdded(e);
+            }
+
+            @Override
+            public void layerRemoving(LayerRemoveEvent e) {
+                if (e.getRemovedLayer() instanceof OsmDataLayer) {
+                    e.getRemovedLayer().removePropertyChangeListener(updateOnRequireUploadChange);
+                }
+                super.layerRemoving(e);
+            }
+        };
+    }
+}
Index: trunk/src/org/openstreetmap/josm/actions/UploadAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 15511)
+++ trunk/src/org/openstreetmap/josm/actions/UploadAction.java	(revision 15513)
@@ -7,5 +7,4 @@
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.beans.PropertyChangeListener;
 import java.util.LinkedList;
 import java.util.List;
@@ -31,6 +30,4 @@
 import org.openstreetmap.josm.gui.io.UploadPrimitivesTask;
 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
-import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
-import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -52,5 +49,5 @@
  * @author imi
  */
-public class UploadAction extends JosmAction {
+public class UploadAction extends AbstractUploadAction {
     /**
      * The list of upload hooks. These hooks will be called one after the other
@@ -94,10 +91,4 @@
         LATE_UPLOAD_HOOKS.add(new DiscardTagsHook());
     }
-
-    private final PropertyChangeListener updateOnRequireUploadChange = evt -> {
-        if (OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP.equals(evt.getPropertyName())) {
-            updateEnabledState();
-        }
-    };
 
     /**
@@ -153,25 +144,4 @@
                 Shortcut.registerShortcut("file:upload", tr("File: {0}", tr("Upload data")), KeyEvent.VK_UP, Shortcut.CTRL_SHIFT), true);
         setHelpId(ht("/Action/Upload"));
-    }
-
-    @Override
-    protected LayerChangeAdapter buildLayerChangeAdapter() {
-        return new LayerChangeAdapter() {
-            @Override
-            public void layerAdded(LayerAddEvent e) {
-                if (e.getAddedLayer() instanceof OsmDataLayer) {
-                    e.getAddedLayer().addPropertyChangeListener(updateOnRequireUploadChange);
-                }
-                super.layerAdded(e);
-            }
-
-            @Override
-            public void layerRemoving(LayerRemoveEvent e) {
-                if (e.getRemovedLayer() instanceof OsmDataLayer) {
-                    e.getRemovedLayer().removePropertyChangeListener(updateOnRequireUploadChange);
-                }
-                super.layerRemoving(e);
-            }
-        };
     }
 
Index: trunk/src/org/openstreetmap/josm/actions/UploadSelectionAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/UploadSelectionAction.java	(revision 15511)
+++ trunk/src/org/openstreetmap/josm/actions/UploadSelectionAction.java	(revision 15513)
@@ -40,5 +40,5 @@
  * @since 2250
  */
-public class UploadSelectionAction extends JosmAction {
+public class UploadSelectionAction extends AbstractUploadAction {
     /**
      * Constructs a new {@code UploadSelectionAction}.
