Index: /trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 13453)
@@ -251,5 +251,5 @@
     protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
         int numWays = 0;
-        if (selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isReadOnly)) {
+        if (selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isLocked)) {
             for (OsmPrimitive osm : selection) {
                 if (osm instanceof Way && !osm.isIncomplete() && ++numWays >= 2) {
Index: /trunk/src/org/openstreetmap/josm/actions/JosmAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/JosmAction.java	(revision 13453)
@@ -350,5 +350,5 @@
     protected final void updateEnabledStateOnCurrentSelection(boolean allowReadOnly) {
         DataSet ds = getLayerManager().getActiveDataSet();
-        if (ds != null && (allowReadOnly || !ds.isReadOnly())) {
+        if (ds != null && (allowReadOnly || !ds.isLocked())) {
             updateEnabledState(ds.getSelected());
         } else {
@@ -366,5 +366,5 @@
     protected final void updateEnabledStateOnModifiableSelection(Collection<? extends OsmPrimitive> selection) {
         setEnabled(selection != null && !selection.isEmpty()
-                && selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isReadOnly));
+                && selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isLocked));
     }
 
Index: /trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 13453)
@@ -366,5 +366,5 @@
     protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
         if (selection == null || selection.isEmpty()
-                || selection.stream().map(OsmPrimitive::getDataSet).anyMatch(DataSet::isReadOnly)) {
+                || selection.stream().map(OsmPrimitive::getDataSet).anyMatch(DataSet::isLocked)) {
             setEnabled(false);
             return;
Index: /trunk/src/org/openstreetmap/josm/actions/MoveNodeAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/MoveNodeAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/MoveNodeAction.java	(revision 13453)
@@ -63,5 +63,5 @@
     protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
         if (selection == null || selection.isEmpty()
-                || selection.stream().map(OsmPrimitive::getDataSet).anyMatch(DataSet::isReadOnly)) {
+                || selection.stream().map(OsmPrimitive::getDataSet).anyMatch(DataSet::isLocked)) {
             setEnabled(false);
             return;
Index: /trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/ReverseWayAction.java	(revision 13453)
@@ -169,5 +169,5 @@
     protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) {
         setEnabled(selection.stream().anyMatch(
-                o -> o instanceof Way && !o.isIncomplete() && !o.getDataSet().isReadOnly()));
+                o -> o instanceof Way && !o.isIncomplete() && !o.getDataSet().isLocked()));
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/SplitWayAction.java	(revision 13453)
@@ -297,5 +297,5 @@
         // Selection still can be wrong, but let SplitWayAction process and tell user what's wrong
         setEnabled(selection != null && !selection.isEmpty()
-                && selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isReadOnly)
+                && selection.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isLocked)
                 && selection.stream().anyMatch(o -> o instanceof Node && !o.isIncomplete()));
     }
Index: /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 13453)
@@ -238,5 +238,5 @@
         private static Stream<OsmDataLayer> getModifiableDataLayers() {
             return MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class)
-                    .stream().filter(l -> !l.isReadOnly());
+                    .stream().filter(OsmDataLayer::isDownloadable);
         }
 
Index: /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/mapmode/MapMode.java	(revision 13453)
@@ -250,5 +250,5 @@
      */
     protected boolean isEditableDataLayer(Layer l) {
-        return l instanceof OsmDataLayer && !((OsmDataLayer) l).isReadOnly();
+        return l instanceof OsmDataLayer && !((OsmDataLayer) l).isLocked();
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/AddSelectionToRelations.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/AddSelectionToRelations.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/AddSelectionToRelations.java	(revision 13453)
@@ -71,5 +71,5 @@
     public void selectionChanged(final Collection<? extends OsmPrimitive> newSelection) {
         GuiHelper.runInEDT(() -> setEnabled(newSelection != null && !newSelection.isEmpty() && !relations.isEmpty()
-                && relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isReadOnly)));
+                && relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isLocked)));
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/DeleteRelationsAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/DeleteRelationsAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/DeleteRelationsAction.java	(revision 13453)
@@ -51,5 +51,5 @@
     @Override
     protected void updateEnabledState() {
-        setEnabled(!relations.isEmpty() && relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isReadOnly));
+        setEnabled(!relations.isEmpty() && relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isLocked));
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/DownloadMembersAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/DownloadMembersAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/DownloadMembersAction.java	(revision 13453)
@@ -48,5 +48,5 @@
     protected void updateEnabledState() {
         setEnabled(!relations.isEmpty() && !Main.isOffline(OnlineResource.OSM_API)
-                && !relations.iterator().next().getDataSet().isReadOnly());
+                && !relations.iterator().next().getDataSet().isLocked());
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/DownloadSelectedIncompleteMembersAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/DownloadSelectedIncompleteMembersAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/DownloadSelectedIncompleteMembersAction.java	(revision 13453)
@@ -68,5 +68,5 @@
     protected void updateEnabledState() {
         setEnabled(!relations.isEmpty() && !incompleteMembers.isEmpty() && !Main.isOffline(OnlineResource.OSM_API)
-                && !relations.iterator().next().getDataSet().isReadOnly());
+                && !relations.iterator().next().getDataSet().isLocked());
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/DuplicateRelationAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/DuplicateRelationAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/DuplicateRelationAction.java	(revision 13453)
@@ -52,5 +52,5 @@
     protected void updateEnabledState() {
         // only one selected relation can be edited
-        setEnabled(relations.size() == 1 && !relations.iterator().next().getDataSet().isReadOnly());
+        setEnabled(relations.size() == 1 && !relations.iterator().next().getDataSet().isLocked());
     }
 }
Index: /trunk/src/org/openstreetmap/josm/actions/relation/EditRelationAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/relation/EditRelationAction.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/actions/relation/EditRelationAction.java	(revision 13453)
@@ -89,5 +89,5 @@
     protected void updateEnabledState() {
         boolean enabled = false;
-        if (relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isReadOnly)) {
+        if (relations.stream().map(Relation::getDataSet).noneMatch(DataSet::isLocked)) {
             for (Relation r : relations) {
                 if (!r.isDeleted()) {
Index: /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 13453)
@@ -104,11 +104,60 @@
  * @author imi
  */
-public final class DataSet extends QuadBucketPrimitiveStore implements Data, ProjectionChangeListener, ReadOnly {
+public final class DataSet extends QuadBucketPrimitiveStore implements Data, ProjectionChangeListener, Lockable {
+
+    /**
+     * Download policy.
+     *
+     * Determines if download from the OSM server is intended, discouraged, or disabled / blocked.
+     * @see UploadPolicy
+     * @since 13453
+     */
+    public enum DownloadPolicy {
+        /**
+         * Normal dataset, download intended.
+         */
+        NORMAL("true"),
+        /**
+         * Download blocked.
+         * Download options completely disabled. Intended for private layers, see #8039.
+         */
+        BLOCKED("never");
+
+        final String xmlFlag;
+
+        DownloadPolicy(String xmlFlag) {
+            this.xmlFlag = xmlFlag;
+        }
+
+        /**
+         * Get the corresponding value of the <code>upload='...'</code> XML-attribute
+         * in the .osm file.
+         * @return value of the <code>download</code> attribute
+         */
+        public String getXmlFlag() {
+            return xmlFlag;
+        }
+
+        /**
+         * Returns the {@code DownloadPolicy} for the given <code>upload='...'</code> XML-attribute
+         * @param xmlFlag <code>download='...'</code> XML-attribute to convert
+         * @return {@code DownloadPolicy} value
+         * @throws IllegalArgumentException for invalid values
+         */
+        public static DownloadPolicy of(String xmlFlag) {
+            for (DownloadPolicy policy : values()) {
+                if (policy.getXmlFlag().equalsIgnoreCase(xmlFlag)) {
+                    return policy;
+                }
+            }
+            throw new IllegalArgumentException(xmlFlag);
+        }
+    }
 
     /**
      * Upload policy.
      *
-     * Determines if upload to the OSM server is intended, discouraged, or
-     * disabled / blocked.
+     * Determines if upload to the OSM server is intended, discouraged, or disabled / blocked.
+     * @see DownloadPolicy
      */
     public enum UploadPolicy {
@@ -173,5 +222,6 @@
 
     private final Storage<OsmPrimitive> allPrimitives = new Storage<>(new Storage.PrimitiveIdHash(), true);
-    private final Map<PrimitiveId, OsmPrimitive> primitivesMap = allPrimitives.foreignKey(new Storage.PrimitiveIdHash());
+    private final Map<PrimitiveId, OsmPrimitive> primitivesMap = allPrimitives
+            .foreignKey(new Storage.PrimitiveIdHash());
     private final CopyOnWriteArrayList<DataSetListener> listeners = new CopyOnWriteArrayList<>();
 
@@ -187,4 +237,5 @@
 
     private String name;
+    private DownloadPolicy downloadPolicy;
     private UploadPolicy uploadPolicy;
     /** Flag used to know if the dataset should not be editable */
@@ -250,5 +301,5 @@
                 primMap.put(w, newWay);
                 List<Node> newNodes = new ArrayList<>();
-                for (Node n: w.getNodes()) {
+                for (Node n : w.getNodes()) {
                     newNodes.add((Node) primMap.get(n));
                 }
@@ -268,5 +319,5 @@
                 Relation newRelation = (Relation) primMap.get(r);
                 List<RelationMember> newMembers = new ArrayList<>();
-                for (RelationMember rm: r.getMembers()) {
+                for (RelationMember rm : r.getMembers()) {
                     newMembers.add(new RelationMember(rm.getRole(), primMap.get(rm.getMember())));
                 }
@@ -378,4 +429,24 @@
         checkModifiable();
         this.version = version;
+    }
+
+    /**
+     * Get the download policy.
+     * @return the download policy
+     * @see #setDownloadPolicy(DownloadPolicy)
+     * @since 13453
+     */
+    public DownloadPolicy getDownloadPolicy() {
+        return this.downloadPolicy;
+    }
+
+    /**
+     * Sets the download policy.
+     * @param downloadPolicy the download policy
+     * @see #getUploadPolicy()
+     * @since 13453
+     */
+    public void setDownloadPolicy(DownloadPolicy downloadPolicy) {
+        this.downloadPolicy = downloadPolicy;
     }
 
@@ -529,5 +600,6 @@
      */
     public Collection<OsmPrimitive> allNonDeletedPhysicalPrimitives() {
-        return getPrimitives(primitive -> !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation));
+        return getPrimitives(
+                primitive -> !primitive.isDeleted() && !primitive.isIncomplete() && !(primitive instanceof Relation));
     }
 
@@ -565,5 +637,6 @@
             if (getPrimitiveById(primitive) != null)
                 throw new DataIntegrityProblemException(
-                        tr("Unable to add primitive {0} to the dataset because it is already included", primitive.toString()));
+                        tr("Unable to add primitive {0} to the dataset because it is already included",
+                                primitive.toString()));
 
             allPrimitives.add(primitive);
@@ -690,5 +763,6 @@
      */
     public Collection<OsmPrimitive> getSelectedNodesAndWays() {
-        return new SubclassFilteredCollection<>(getSelected(), primitive -> primitive instanceof Node || primitive instanceof Way);
+        return new SubclassFilteredCollection<>(getSelected(),
+                primitive -> primitive instanceof Node || primitive instanceof Way);
     }
 
@@ -1006,6 +1080,7 @@
         OsmPrimitive result = getPrimitiveById(primitiveId);
         if (result == null && primitiveId != null) {
-            Logging.warn(tr("JOSM expected to find primitive [{0} {1}] in dataset but it is not there. Please report this "
-                    + "at {2}. This is not a critical error, it should be safe to continue in your work.",
+            Logging.warn(tr(
+                    "JOSM expected to find primitive [{0} {1}] in dataset but it is not there. Please report this "
+                            + "at {2}. This is not a critical error, it should be safe to continue in your work.",
                     primitiveId.getType(), Long.toString(primitiveId.getUniqueId()), Main.getJOSMWebsite()));
             Logging.error(new Exception());
@@ -1115,5 +1190,5 @@
      */
     public boolean isModified() {
-        for (OsmPrimitive p: allPrimitives) {
+        for (OsmPrimitive p : allPrimitives) {
             if (p.isModified())
                 return true;
@@ -1128,5 +1203,5 @@
      */
     public boolean requiresUploadToServer() {
-        for (OsmPrimitive p: allPrimitives) {
+        for (OsmPrimitive p : allPrimitives) {
             if (APIOperation.of(p) != null)
                 return true;
@@ -1199,5 +1274,5 @@
                 try {
                     if (eventsToFire.size() < MAX_SINGLE_EVENTS) {
-                        for (AbstractDatasetChangedEvent event: eventsToFire) {
+                        for (AbstractDatasetChangedEvent event : eventsToFire) {
                             fireEventToListeners(event);
                         }
@@ -1219,5 +1294,5 @@
 
     private void fireEventToListeners(AbstractDatasetChangedEvent event) {
-        for (DataSetListener listener: listeners) {
+        for (DataSetListener listener : listeners) {
             event.fire(listener);
         }
@@ -1260,5 +1335,6 @@
 
     void fireChangesetIdChanged(OsmPrimitive primitive, int oldChangesetId, int newChangesetId) {
-        fireEvent(new ChangesetIdChangedEvent(this, Collections.singletonList(primitive), oldChangesetId, newChangesetId));
+        fireEvent(new ChangesetIdChangedEvent(this, Collections.singletonList(primitive), oldChangesetId,
+                newChangesetId));
     }
 
@@ -1283,8 +1359,9 @@
      */
     public void invalidateEastNorthCache() {
-        if (Main.getProjection() == null) return; // sanity check
+        if (Main.getProjection() == null)
+            return; // sanity check
         beginUpdate();
         try {
-            for (Node n: getNodes()) {
+            for (Node n : getNodes()) {
                 n.invalidateEastNorthCache();
             }
@@ -1326,5 +1403,5 @@
         try {
             clearSelection();
-            for (OsmPrimitive primitive:allPrimitives) {
+            for (OsmPrimitive primitive : allPrimitives) {
                 primitive.setDataset(null);
             }
@@ -1343,5 +1420,5 @@
     public void deleteInvisible() {
         checkModifiable();
-        for (OsmPrimitive primitive:allPrimitives) {
+        for (OsmPrimitive primitive : allPrimitives) {
             if (!primitive.isVisible()) {
                 primitive.setDeleted(true);
@@ -1454,5 +1531,5 @@
 
     @Override
-    public void setReadOnly() {
+    public void lock() {
         if (!isReadOnly.compareAndSet(false, true)) {
             Logging.warn("Trying to set readOnly flag on a readOnly dataset ", getName());
@@ -1461,5 +1538,5 @@
 
     @Override
-    public void unsetReadOnly() {
+    public void unlock() {
         if (!isReadOnly.compareAndSet(true, false)) {
             Logging.warn("Trying to unset readOnly flag on a non-readOnly dataset ", getName());
@@ -1468,5 +1545,5 @@
 
     @Override
-    public boolean isReadOnly() {
+    public boolean isLocked() {
         return isReadOnly.get();
     }
@@ -1477,5 +1554,5 @@
      */
     private void checkModifiable() {
-        if (isReadOnly()) {
+        if (isLocked()) {
             throw new IllegalStateException("DataSet is read-only");
         }
Index: /trunk/src/org/openstreetmap/josm/data/osm/Lockable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/Lockable.java	(revision 13453)
+++ /trunk/src/org/openstreetmap/josm/data/osm/Lockable.java	(revision 13453)
@@ -0,0 +1,25 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+/**
+ * To be implemented by modifiable objects to offer a "read-only/locked" mode.
+ * @since 13453
+ */
+public interface Lockable {
+
+    /**
+     * Enables the read-only/locked mode.
+     */
+    void lock();
+
+    /**
+     * Disables the read-only/locked mode.
+     */
+    void unlock();
+
+    /**
+     * Determines if this is read-only/locked (thus it cannot be modified).
+     * @return {@code true} if this is read-only/locked
+     */
+    boolean isLocked();
+}
Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 13453)
@@ -279,5 +279,5 @@
      */
     protected final void checkDatasetNotReadOnly() {
-        if (dataSet != null && dataSet.isReadOnly())
+        if (dataSet != null && dataSet.isLocked())
             throw new DataIntegrityProblemException("Primitive cannot be modified in read-only dataset: " + toString());
     }
Index: unk/src/org/openstreetmap/josm/data/osm/ReadOnly.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/ReadOnly.java	(revision 13452)
+++ 	(revision )
@@ -1,25 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.data.osm;
-
-/**
- * To be implemented by modifiable objects to offer a "read-only" mode.
- * @since 13434
- */
-public interface ReadOnly {
-
-    /**
-     * Enables the read-only mode.
-     */
-    void setReadOnly();
-
-    /**
-     * Disables the read-only mode.
-     */
-    void unsetReadOnly();
-
-    /**
-     * Determines if this is read-only (thus it cannot be modified).
-     * @return {@code true} if this is read-only
-     */
-    boolean isReadOnly();
-}
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/AbstractMapRenderer.java	(revision 13453)
@@ -128,5 +128,5 @@
      */
     public void drawVirtualNodes(DataSet data, BBox bbox) {
-        if (virtualNodeSize == 0 || data == null || bbox == null || data.isReadOnly())
+        if (virtualNodeSize == 0 || data == null || bbox == null || data.isLocked())
             return;
         // print normal virtual nodes
Index: /trunk/src/org/openstreetmap/josm/data/validation/TestError.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/TestError.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/data/validation/TestError.java	(revision 13453)
@@ -360,5 +360,5 @@
     public boolean isFixable() {
         return (fixingCommand != null || ((tester != null) && tester.isFixable(this)))
-                && primitives.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isReadOnly);
+                && primitives.stream().map(OsmPrimitive::getDataSet).noneMatch(DataSet::isLocked);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/RelationListDialog.java	(revision 13453)
@@ -353,5 +353,5 @@
             DataSet ds = MainApplication.getLayerManager().getActiveDataSet();
             if (ds != null && isDoubleClick(e)) {
-                if (e.isControlDown() && !ds.isReadOnly()) {
+                if (e.isControlDown() && !ds.isLocked()) {
                     editCurrentRelation();
                 } else {
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PresetListPanel.java	(revision 13453)
@@ -41,5 +41,5 @@
             int answer = t.showDialog(selection, false);
 
-            if (answer == TaggingPreset.DIALOG_ANSWER_APPLY && !selection.iterator().next().getDataSet().isReadOnly()) {
+            if (answer == TaggingPreset.DIALOG_ANSWER_APPLY && !selection.iterator().next().getDataSet().isLocked()) {
                 presetHandler.updateTags(t.getChangedTags());
             }
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesDialog.java	(revision 13453)
@@ -490,5 +490,5 @@
         MainApplication.getMap().relationListDialog.selectRelation(relation);
         OsmDataLayer layer = MainApplication.getLayerManager().getActiveDataLayer();
-        if (!layer.isReadOnly()) {
+        if (!layer.isLocked()) {
             RelationEditor.getEditor(
                     layer, relation, ((MemberInfo) membershipData.getValueAt(row, 1)).role).setVisible(true);
@@ -647,5 +647,5 @@
 
         DataSet ds = Main.main.getActiveDataSet();
-        boolean isReadOnly = ds != null && ds.isReadOnly();
+        boolean isReadOnly = ds != null && ds.isLocked();
         boolean hasSelection = !newSel.isEmpty();
         boolean hasTags = hasSelection && tagData.getRowCount() > 0;
@@ -1060,5 +1060,5 @@
         protected final void updateEnabledState() {
             DataSet ds = Main.main.getActiveDataSet();
-            setEnabled(ds != null && !ds.isReadOnly() &&
+            setEnabled(ds != null && !ds.isLocked() &&
                     ((tagTable != null && tagTable.getSelectedRowCount() >= 1)
                     || (membershipTable != null && membershipTable.getSelectedRowCount() > 0)
@@ -1116,5 +1116,5 @@
         protected void updateEnabledState() {
             DataSet ds = Main.main.getActiveDataSet();
-            setEnabled(ds != null && !ds.isReadOnly() &&
+            setEnabled(ds != null && !ds.isLocked() &&
                     ((tagTable != null && tagTable.getSelectedRowCount() == 1)
                     ^ (membershipTable != null && membershipTable.getSelectedRowCount() == 1)
@@ -1271,5 +1271,5 @@
             Collection<OsmPrimitive> sel = Main.main.getInProgressSelection();
             String clipboard = ClipboardUtils.getClipboardStringContent();
-            if (sel.isEmpty() || clipboard == null || sel.iterator().next().getDataSet().isReadOnly())
+            if (sel.isEmpty() || clipboard == null || sel.iterator().next().getDataSet().isLocked())
                 return;
             MainApplication.undoRedo.add(new ChangePropertyCommand(sel, key, Utils.strip(clipboard)));
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/properties/TagEditHelper.java	(revision 13453)
@@ -564,5 +564,5 @@
         public void setupDialog() {
             super.setupDialog();
-            buttons.get(0).setEnabled(!Main.main.getActiveDataSet().isReadOnly());
+            buttons.get(0).setEnabled(!Main.main.getActiveDataSet().isLocked());
             final Dimension size = getSize();
             // Set resizable only in width
Index: /trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 13453)
@@ -220,7 +220,7 @@
         // partially uploaded. Better run on EDT.
         Runnable r = () -> {
-            boolean readOnly = layer.isReadOnly();
+            boolean readOnly = layer.isLocked();
             if (readOnly) {
-                layer.unsetReadOnly();
+                layer.unlock();
             }
             try {
@@ -230,5 +230,5 @@
             } finally {
                 if (readOnly) {
-                    layer.setReadOnly();
+                    layer.lock();
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractModifiableLayer.java	(revision 13453)
@@ -2,5 +2,5 @@
 package org.openstreetmap.josm.gui.layer;
 
-import org.openstreetmap.josm.data.osm.ReadOnly;
+import org.openstreetmap.josm.data.osm.Lockable;
 import org.openstreetmap.josm.gui.io.AbstractIOTask;
 import org.openstreetmap.josm.gui.io.AbstractUploadDialog;
@@ -11,5 +11,5 @@
  * @since 7358
  */
-public abstract class AbstractModifiableLayer extends Layer implements UploadToServer, SaveToFile, ReadOnly {
+public abstract class AbstractModifiableLayer extends Layer implements DownloadFromServer, UploadToServer, SaveToFile, Lockable {
 
     /**
@@ -19,4 +19,10 @@
     public AbstractModifiableLayer(String name) {
         super(name);
+    }
+
+    @Override
+    public boolean isDownloadable() {
+        // Override if needed
+        return false;
     }
 
@@ -83,15 +89,15 @@
 
     @Override
-    public void setReadOnly() {
+    public void lock() {
         // Override if needed
     }
 
     @Override
-    public void unsetReadOnly() {
+    public void unlock() {
         // Override if needed
     }
 
     @Override
-    public boolean isReadOnly() {
+    public boolean isLocked() {
         // Override if needed
         return false;
Index: /trunk/src/org/openstreetmap/josm/gui/layer/DownloadFromServer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/DownloadFromServer.java	(revision 13453)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/DownloadFromServer.java	(revision 13453)
@@ -0,0 +1,19 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.layer;
+
+/**
+ * Interface for layers that can download data.
+ * @see UploadToServer
+ * @since 13453
+ */
+public interface DownloadFromServer {
+
+    /**
+     * Determines if the layer is able to download data and implements the
+     * {@code DownloadFromServer} interface. A layer that implements the
+     * {@code DownloadFromServer} interface must return {@code true}.
+     *
+     * @return {@code true} if the layer is able to download data; {@code false}, otherwise
+     */
+    boolean isDownloadable();
+}
Index: /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/MainLayerManager.java	(revision 13453)
@@ -376,5 +376,5 @@
      */
     public synchronized OsmDataLayer getEditLayer() {
-        if (dataLayer != null && !dataLayer.isReadOnly())
+        if (dataLayer != null && !dataLayer.isLocked())
             return dataLayer;
         else
@@ -402,5 +402,5 @@
      */
     public synchronized DataSet getEditDataSet() {
-        if (dataLayer != null && !dataLayer.isReadOnly()) {
+        if (dataLayer != null && !dataLayer.isLocked()) {
             return dataLayer.data;
         } else {
@@ -509,5 +509,5 @@
         GuiHelper.assertCallFromEdt();
         layer.setUploadInProgress();
-        layer.setReadOnly();
+        layer.lock();
 
         // Reset only the edit layer as empty
@@ -528,5 +528,5 @@
     public synchronized void processLayerAfterUpload(OsmDataLayer layer) {
         GuiHelper.assertCallFromEdt();
-        layer.unsetReadOnly();
+        layer.unlock();
         layer.unsetUploadInProgress();
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java	(revision 13453)
@@ -134,4 +134,9 @@
 
     @Override
+    public boolean isDownloadable() {
+        return true;
+    }
+
+    @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 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 13453)
@@ -64,4 +64,5 @@
 import org.openstreetmap.josm.data.osm.DataSelectionListener;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSet.DownloadPolicy;
 import org.openstreetmap.josm.data.osm.DataSet.UploadPolicy;
 import org.openstreetmap.josm.data.osm.DataSetMerger;
@@ -421,5 +422,8 @@
     public Icon getIcon() {
         ImageProvider base = getBaseIconProvider().setMaxSize(ImageSizes.LAYER);
-        if (isUploadDiscouraged() || data.getUploadPolicy() == UploadPolicy.BLOCKED) {
+        if (data.getDownloadPolicy() != null && data.getDownloadPolicy() != DownloadPolicy.NORMAL) {
+            base.addOverlay(new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.0, 1.0, 0.5));
+        }
+        if (data.getUploadPolicy() != null && data.getUploadPolicy() != UploadPolicy.NORMAL) {
             base.addOverlay(new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0));
         }
@@ -428,5 +432,5 @@
             // If the layer is being uploaded then change the default icon to a clock
             base = new ImageProvider("clock").setMaxSize(ImageSizes.LAYER);
-        } else if (isReadOnly()) {
+        } else if (isLocked()) {
             // If the layer is read only then change the default icon to a lock
             base = new ImageProvider("lock").setMaxSize(ImageSizes.LAYER);
@@ -940,6 +944,11 @@
 
     @Override
+    public boolean isDownloadable() {
+        return data.getDownloadPolicy() != DownloadPolicy.BLOCKED && !isLocked();
+    }
+
+    @Override
     public boolean isUploadable() {
-        return data.getUploadPolicy() != UploadPolicy.BLOCKED;
+        return data.getUploadPolicy() != UploadPolicy.BLOCKED && !isLocked();
     }
 
@@ -1031,9 +1040,4 @@
     }
 
-    /**
-     * Determines if upload is being discouraged.
-     * (i.e. this dataset contains private data which should not be uploaded)
-     * @return {@code true} if upload is being discouraged, {@code false} otherwise
-     */
     @Override
     public final boolean isUploadDiscouraged() {
@@ -1174,16 +1178,16 @@
 
     @Override
-    public void setReadOnly() {
-        data.setReadOnly();
-    }
-
-    @Override
-    public void unsetReadOnly() {
-        data.unsetReadOnly();
-    }
-
-    @Override
-    public boolean isReadOnly() {
-        return data.isReadOnly();
+    public void lock() {
+        data.lock();
+    }
+
+    @Override
+    public void unlock() {
+        data.unlock();
+    }
+
+    @Override
+    public boolean isLocked() {
+        return data.isLocked();
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/UploadToServer.java	(revision 13453)
@@ -8,4 +8,5 @@
 /**
  * Interface for layers that can upload data.
+ * @see DownloadFromServer
  * @since 9751
  */
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 13453)
@@ -493,5 +493,5 @@
 
             answer = new PresetDialog(p, title, preset_name_label ? null : (ImageIcon) getValue(Action.SMALL_ICON),
-                    sel.isEmpty() || sel.iterator().next().getDataSet().isReadOnly(), showNewRelation).getValue();
+                    sel.isEmpty() || sel.iterator().next().getDataSet().isLocked(), showNewRelation).getValue();
         }
         if (!showNewRelation && answer == 2)
Index: /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/io/DiffResultProcessor.java	(revision 13453)
@@ -123,7 +123,7 @@
         boolean readOnly = false;
         if (ds != null) {
-            readOnly = ds.isReadOnly();
+            readOnly = ds.isLocked();
             if (readOnly) {
-                ds.unsetReadOnly();
+                ds.unlock();
             }
             ds.beginUpdate();
@@ -158,5 +158,5 @@
                 ds.endUpdate();
                 if (readOnly) {
-                    ds.setReadOnly();
+                    ds.lock();
                 }
             }
Index: /trunk/src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 13452)
+++ /trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 13453)
@@ -12,4 +12,5 @@
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -27,4 +28,5 @@
 import org.openstreetmap.josm.data.osm.Changeset;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSet.DownloadPolicy;
 import org.openstreetmap.josm.data.osm.DataSet.UploadPolicy;
 import org.openstreetmap.josm.data.osm.Node;
@@ -139,14 +141,8 @@
         }
         ds.setVersion(v);
-        String upload = parser.getAttributeValue(null, "upload");
-        if (upload != null) {
-            try {
-                ds.setUploadPolicy(UploadPolicy.of(upload));
-            } catch (IllegalArgumentException e) {
-                throwException(MessageFormat.format("Illegal value for attribute ''upload''. Got ''{0}''.", upload), e);
-            }
-        }
-        if ("true".equalsIgnoreCase(parser.getAttributeValue(null, "read-only"))) {
-            ds.setReadOnly();
+        parsePolicy("download", policy -> ds.setDownloadPolicy(DownloadPolicy.of(policy)));
+        parsePolicy("upload", policy -> ds.setUploadPolicy(UploadPolicy.of(policy)));
+        if ("true".equalsIgnoreCase(parser.getAttributeValue(null, "locked"))) {
+            ds.lock();
         }
         String generator = parser.getAttributeValue(null, "generator");
@@ -185,4 +181,15 @@
             } else if (event == XMLStreamConstants.END_ELEMENT) {
                 return;
+            }
+        }
+    }
+
+    private void parsePolicy(String key, Consumer<String> consumer) throws XMLStreamException {
+        String policy = parser.getAttributeValue(null, key);
+        if (policy != null) {
+            try {
+                consumer.accept(policy);
+            } catch (IllegalArgumentException e) {
+                throwException(MessageFormat.format("Illegal value for attribute ''{0}''. Got ''{1}''.", key, policy), e);
             }
         }
@@ -621,13 +628,13 @@
             progressMonitor.worked(1);
 
-            boolean readOnly = getDataSet().isReadOnly();
+            boolean readOnly = getDataSet().isLocked();
 
             progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
             if (readOnly) {
-                getDataSet().unsetReadOnly();
+                getDataSet().unlock();
             }
             prepareDataSet();
             if (readOnly) {
-                getDataSet().setReadOnly();
+                getDataSet().lock();
             }
             progressMonitor.worked(1);
@@ -641,6 +648,6 @@
             }
             // Make sure postprocessors did not change the read-only state
-            if (readOnly && !getDataSet().isReadOnly()) {
-                getDataSet().setReadOnly();
+            if (readOnly && !getDataSet().isLocked()) {
+                getDataSet().lock();
             }
             return getDataSet();
