Index: /trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/Main.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/Main.java	(revision 9751)
@@ -1046,5 +1046,8 @@
             }
             AbstractModifiableLayer odl = (AbstractModifiableLayer) l;
-            if ((odl.requiresSaveToFile() || (odl.requiresUploadToServer() && !odl.isUploadDiscouraged())) && odl.isModified()) {
+            if (odl.isModified() &&
+                    ((!odl.isSavable() && !odl.isUploadable()) ||
+                     odl.requiresSaveToFile() ||
+                     (odl.requiresUploadToServer() && !odl.isUploadDiscouraged()))) {
                 layersWithUnmodifiedChanges.add(odl);
             }
Index: /trunk/src/org/openstreetmap/josm/gui/io/ActionFlagsTableCell.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/ActionFlagsTableCell.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/io/ActionFlagsTableCell.java	(revision 9751)
@@ -57,5 +57,4 @@
         ActionMap am = getActionMap();
         for (final JCheckBox b : checkBoxes) {
-            add(b, GBC.eol().fill(GBC.HORIZONTAL));
             b.setPreferredSize(new Dimension(b.getPreferredSize().width, 19));
             b.addActionListener(al);
@@ -68,10 +67,4 @@
             });
         }
-
-        setToolTipText(tr("<html>"+
-            "Select which actions to perform for this layer, if you click the leftmost button.<br/>"+
-            "Check \"upload\" to upload the changes to the OSM server.<br/>"+
-            "Check \"Save\" to save the layer to the file specified on the left."+
-            "</html>"));
     }
 
@@ -91,6 +84,28 @@
     }
 
+    private void updatePanel(SaveLayerInfo info) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("<html>");
+        sb.append(tr("Select which actions to perform for this layer, if you click the leftmost button."));
+        removeAll();
+        if (info != null) {
+            if (info.isUploadable()) {
+                sb.append("<br/>");
+                sb.append(tr("Check \"Upload\" to upload the changes to the OSM server."));
+                add(checkBoxes[0], GBC.eol().fill(GBC.HORIZONTAL));
+            }
+            if (info.isSavable()) {
+                sb.append("<br/>");
+                sb.append(tr("Check \"Save\" to save the layer to the file specified on the left."));
+                add(checkBoxes[1], GBC.eol().fill(GBC.HORIZONTAL));
+            }
+        }
+        sb.append("</html>");
+        setToolTipText(sb.toString());
+    }
+
     @Override
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
+        updatePanel((SaveLayerInfo) value);
         updateCheckboxes(value);
         return this;
@@ -138,4 +153,5 @@
     @Override
     public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
+        updatePanel((SaveLayerInfo) value);
         updateCheckboxes(value);
         return this;
Index: /trunk/src/org/openstreetmap/josm/gui/io/LayerNameAndFilePathTableCell.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/LayerNameAndFilePathTableCell.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/io/LayerNameAndFilePathTableCell.java	(revision 9751)
@@ -81,9 +81,11 @@
         StringBuilder sb = new StringBuilder();
         sb.append("<html>")
-          .append(addLblLayerName(info))
-          .append("<br>");
-        add(btnFileChooser, GBC.std());
-        sb.append(addLblFilename(info))
-          .append("</html>");
+          .append(addLblLayerName(info));
+        if (info.isSavable()) {
+            add(btnFileChooser, GBC.std());
+            sb.append("<br>")
+              .append(addLblFilename(info));
+        }
+        sb.append("</html>");
         setToolTipText(sb.toString());
         return this;
@@ -99,13 +101,15 @@
         StringBuilder sb = new StringBuilder();
         sb.append("<html>")
-          .append(addLblLayerName(info))
-          .append("<br/>");
-
-        add(btnFileChooser, GBC.std());
-        add(tfFilename, GBC.eol().fill(GBC.HORIZONTAL).insets(1, 0, 0, 0));
-        tfFilename.selectAll();
-
-        sb.append(tfFilename.getToolTipText())
-          .append("</html>");
+          .append(addLblLayerName(info));
+
+        if (info.isSavable()) {
+            add(btnFileChooser, GBC.std());
+            add(tfFilename, GBC.eol().fill(GBC.HORIZONTAL).insets(1, 0, 0, 0));
+            tfFilename.selectAll();
+
+            sb.append("<br>")
+              .append(tfFilename.getToolTipText());
+        }
+        sb.append("</html>");
         setToolTipText(sb.toString());
         return this;
Index: /trunk/src/org/openstreetmap/josm/gui/io/SaveLayerInfo.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/SaveLayerInfo.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/io/SaveLayerInfo.java	(revision 9751)
@@ -47,4 +47,22 @@
 
     /**
+     * Replies true if the layer can be saved to a file
+     *
+     * @return {@code true} if the layer can be saved to a file; {@code false} otherwise
+     */
+    public boolean isSavable() {
+        return layer.isSavable();
+    }
+
+    /**
+     * Replies true if the layer can be uploaded to a server
+     *
+     * @return {@code true} if the layer can be uploaded to a server; {@code false} otherwise
+     */
+    public boolean isUploadable() {
+        return layer.isUploadable();
+    }
+
+    /**
      * Replies true if preconditions should be checked before saving; false, otherwise
      *
@@ -81,5 +99,5 @@
      */
     public void setDoSaveToFile(boolean doSaveToFile) {
-        this.doSaveToFile = doSaveToFile;
+        this.doSaveToFile = isSavable() ? doSaveToFile : false;
     }
 
@@ -94,11 +112,10 @@
 
     /**
-     * Sets whether this layer should be uploaded to a file
+     * Sets whether this layer should be uploaded to a server
      *
      * @param doUploadToServer {@code true} to upload; {@code false}, to skip uploading
      */
-
     public void setDoUploadToServer(boolean doUploadToServer) {
-        this.doUploadToServer = doUploadToServer;
+        this.doUploadToServer = isUploadable() ? doUploadToServer : false;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersModel.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersModel.java	(revision 9751)
@@ -103,13 +103,16 @@
     @Override
     public void setValueAt(Object value, int row, int column) {
+        final SaveLayerInfo info = this.layerInfo.get(row);
         switch(column) {
         case columnFilename:
-            this.layerInfo.get(row).setFile((File) value);
-            this.layerInfo.get(row).setDoSaveToFile(true);
+            info.setFile((File) value);
+            if (info.isSavable()) {
+                info.setDoSaveToFile(true);
+            }
             break;
         case columnActions:
             boolean[] values = (boolean[]) value;
-            this.layerInfo.get(row).setDoUploadToServer(values[0]);
-            this.layerInfo.get(row).setDoSaveToFile(values[1]);
+            info.setDoUploadToServer(values[0]);
+            info.setDoSaveToFile(values[1]);
             break;
         }
Index: /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersTableColumnModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersTableColumnModel.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/io/SaveLayersTableColumnModel.java	(revision 9751)
@@ -47,5 +47,7 @@
 
                 } else {
-                    panel.add(pnlEmpty, defaultCellStyle);
+                    if (info.isUploadable()) {
+                        panel.add(pnlEmpty, defaultCellStyle);
+                    }
                     if (info.getLayer().requiresUploadToServer()) {
                         sb.append(tr("Layer ''{0}'' has modifications which are discouraged to be uploaded.", info.getName()));
@@ -61,5 +63,7 @@
                             info.getName(), info.getFile().toString()));
                 } else {
-                    panel.add(pnlEmpty, defaultCellStyle);
+                    if (info.isSavable()) {
+                        panel.add(pnlEmpty, defaultCellStyle);
+                    }
                     sb.append(tr("Layer ''{0}'' has no modifications to be saved.", info.getName()));
                 }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java	(revision 9751)
@@ -10,5 +10,5 @@
  * @since 7358
  */
-public abstract class AbstractModifiableLayer extends Layer {
+public abstract class AbstractModifiableLayer extends Layer implements UploadToServer, SaveToFile {
 
     /**
@@ -21,4 +21,16 @@
 
     /**
+     * Determines if the layer is able to upload data and implements the
+     * {@code UploadToServer} interface.
+     *
+     * @return true if the layer is able to upload data; false, otherwise
+     */
+    @Override
+    public boolean isUploadable() {
+        // Override if needed
+        return false;
+    }
+
+    /**
      * Determines if the data managed by this layer needs to be uploaded to
      * the server because it contains modified data.
@@ -27,4 +39,5 @@
      * the server because it contains modified data; false, otherwise
      */
+    @Override
     public boolean requiresUploadToServer() {
         // Override if needed
@@ -40,4 +53,5 @@
      * @return true if the data managed by this layer needs to be saved to a file
      */
+    @Override
     public boolean requiresSaveToFile() {
         // Override if needed
@@ -51,4 +65,5 @@
      * @return true if upload is discouraged for this layer; false, otherwise
      */
+    @Override
     public boolean isUploadDiscouraged() {
         // Override if needed
@@ -65,4 +80,5 @@
      * Initializes the layer after a successful save of data to a file.
      */
+    @Override
     public void onPostSaveToFile() {
         // Override if needed
@@ -72,4 +88,5 @@
      * Initializes the layer after a successful upload to the server.
      */
+    @Override
     public void onPostUploadToServer() {
         // Override if needed
@@ -81,4 +98,5 @@
      * @return a new {@code AbstractIOTask} for uploading data, or {@code null} if not applicable
      */
+    @Override
     public AbstractIOTask createUploadTask(ProgressMonitor monitor) {
         // Override if needed
@@ -90,4 +108,5 @@
      * @return the upload dialog for this layer, or {@code null} if not applicable
      */
+    @Override
     public AbstractUploadDialog getUploadDialog() {
         // Override if needed
Index: /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 9751)
@@ -48,5 +48,5 @@
  * @since 7522
  */
-public class NoteLayer extends AbstractModifiableLayer implements MouseListener {
+public class NoteLayer extends AbstractModifiableLayer implements MouseListener, UploadToServer, SaveToFile {
 
     private final NoteData noteData;
@@ -83,4 +83,9 @@
     public boolean isModified() {
         return noteData.isModified();
+    }
+
+    @Override
+    public boolean isUploadable() {
+        return true;
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 9751)
@@ -109,5 +109,5 @@
  * @since 17
  */
-public class OsmDataLayer extends AbstractModifiableLayer implements Listener, SelectionChangedListener {
+public class OsmDataLayer extends AbstractModifiableLayer implements Listener, SelectionChangedListener, UploadToServer, SaveToFile {
     /** Property used to know if this layer has to be saved on disk */
     public static final String REQUIRES_SAVE_TO_DISK_PROP = OsmDataLayer.class.getName() + ".requiresSaveToDisk";
@@ -836,4 +836,9 @@
 
     @Override
+    public boolean isUploadable() {
+        return true;
+    }
+
+    @Override
     public boolean requiresUploadToServer() {
         return requiresUploadToServer;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/SaveToFile.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/SaveToFile.java	(revision 9751)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/SaveToFile.java	(revision 9751)
@@ -0,0 +1,33 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer;
+
+/**
+ * Interface for layers that can save data to a file.
+ * @since 9751
+ */
+public interface SaveToFile {
+
+    /**
+     * Replies the savable state of the layer (i.e. if it can be saved through
+     * a "File-&gt;Save" dialog).  A layer that implements the
+     * {@code SaveToFile} interface must return {@code true}.
+     *
+     * @return {@code true} if the layer can be saved to a file; {@code false}, otherwise
+     */
+    boolean isSavable();
+
+    /**
+     * Determines if the data managed by this layer needs to be saved to
+     * a file. Only replies true if a file is assigned to this layer and
+     * if the data managed by this layer has been modified since the last
+     * save operation to the file.
+     *
+     * @return {@code true} if the data managed by this layer needs to be saved to a file; {@code false}, otherwise
+     */
+    boolean requiresSaveToFile();
+
+    /**
+     * Initializes the layer after a successful save of data to a file.
+     */
+    void onPostSaveToFile();
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java	(revision 9751)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java	(revision 9751)
@@ -0,0 +1,58 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer;
+
+import org.openstreetmap.josm.gui.io.AbstractIOTask;
+import org.openstreetmap.josm.gui.io.AbstractUploadDialog;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+
+/**
+ * Interface for layers that can upload data.
+ * @since 9751
+ */
+public interface UploadToServer {
+
+    /**
+     * Determines if the layer is able to upload data and implements the
+     * {@code UploadToServer} interface.  A layer that implements the
+     * {@code UploadToServer} interface must return {@code true}.
+     *
+     * @return {@code true} if the layer is able to upload data; {@code false}, otherwise
+     */
+    boolean isUploadable();
+
+    /**
+     * Determines if the data managed by this layer needs to be uploaded to
+     * the server because it contains modified data.
+     *
+     * @return {@code true} if the data managed by this layer needs to be
+     *         uploaded to the server because it contains modified data;
+     *         {@code false}, otherwise
+     */
+    boolean requiresUploadToServer();
+
+    /**
+     * Determines if upload of data managed by this layer is discouraged.
+     * This feature allows to use "private" data layers.
+     *
+     * @return {@code true} if upload is discouraged for this layer; {@code false}, otherwise
+     */
+    boolean isUploadDiscouraged();
+
+    /**
+     * Initializes the layer after a successful upload to the server.
+     */
+    void onPostUploadToServer();
+
+    /**
+     * Creates a new {@code AbstractIOTask} for uploading data.
+     * @param monitor The progress monitor
+     * @return a new {@code AbstractIOTask} for uploading data, or {@code null} if not applicable
+     */
+    AbstractIOTask createUploadTask(ProgressMonitor monitor);
+
+    /**
+     * Returns the upload dialog for this layer.
+     * @return the upload dialog for this layer, or {@code null} if not applicable
+     */
+    AbstractUploadDialog getUploadDialog();
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 9750)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/geoimage/GeoImageLayer.java	(revision 9751)
@@ -60,4 +60,5 @@
 import org.openstreetmap.josm.gui.layer.JumpToMarkerActions.JumpToNextMarker;
 import org.openstreetmap.josm.gui.layer.JumpToMarkerActions.JumpToPreviousMarker;
+import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
 import org.openstreetmap.josm.gui.util.GuiHelper;
@@ -69,5 +70,5 @@
  * Layer displaying geottaged pictures.
  */
-public class GeoImageLayer extends Layer implements PropertyChangeListener, JumpToMarkerLayer {
+public class GeoImageLayer extends AbstractModifiableLayer implements PropertyChangeListener, JumpToMarkerLayer {
 
     private static List<Action> menuAdditions = new LinkedList<>();
@@ -369,4 +370,21 @@
     public String getToolTipText() {
         return infoText();
+    }
+
+    /**
+     * Determines if data managed by this layer has been modified.  That is
+     * the case if one image has modified GPS data.
+     * @return {@code true} if data has been modified; {@code false}, otherwise
+     */
+    @Override
+    public boolean isModified() {
+        if (data != null) {
+            for (ImageEntry e : data) {
+                if (e.hasNewGpsData()) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
