Index: trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmUtils.java	(revision 18918)
@@ -36,5 +36,5 @@
     /**
      * Discouraged synonym for {@link #TRUE_VALUE}
-     * @deprecated since xxx, use {@link #TRUE_VALUE} instead.
+     * @deprecated since 18801, use {@link #TRUE_VALUE} instead.
      */
     @Deprecated
@@ -42,5 +42,5 @@
     /**
      * Discouraged synonym for {@link #FALSE_VALUE}
-     * @deprecated since xxx, use {@link #FALSE_VALUE} instead.
+     * @deprecated since 18801, use {@link #FALSE_VALUE} instead.
      */
     @Deprecated
@@ -48,5 +48,5 @@
     /**
      * Discouraged synonym for {@link #REVERSE_VALUE}
-     * @deprecated since xxx, use {@link #REVERSE_VALUE} instead.
+     * @deprecated since 18801, use {@link #REVERSE_VALUE} instead.
      */
     @Deprecated
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 18918)
@@ -25,4 +25,5 @@
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.OptionalInt;
 import java.util.Set;
@@ -38,6 +39,8 @@
 import org.openstreetmap.josm.command.Command;
 import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.AbstractPrimitive;
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
@@ -63,11 +66,17 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.Check;
 import org.openstreetmap.josm.gui.tagging.presets.items.CheckGroup;
+import org.openstreetmap.josm.gui.tagging.presets.items.ComboMultiSelect;
+import org.openstreetmap.josm.gui.tagging.presets.items.Key;
 import org.openstreetmap.josm.gui.tagging.presets.items.KeyedItem;
+import org.openstreetmap.josm.gui.tagging.presets.items.PresetListEntry;
+import org.openstreetmap.josm.gui.tagging.presets.items.RegionSpecific;
 import org.openstreetmap.josm.gui.widgets.EditableList;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.spi.preferences.Config;
 import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.JosmRuntimeException;
 import org.openstreetmap.josm.tools.Logging;
 import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Territories;
 import org.openstreetmap.josm.tools.Utils;
 
@@ -132,4 +141,5 @@
      */
     public static final String PREF_CHECK_PRESETS_TYPES = PREFIX + ".checkPresetsTypes";
+    public static final String PREF_CHECK_REGIONS = PREFIX + ".checkPresetsRegions";
 
     /**
@@ -160,4 +170,5 @@
      */
     public static final String PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD = PREF_CHECK_PRESETS_TYPES + BEFORE_UPLOAD;
+    public static final String PREF_CHECK_REGIONS_BEFORE_UPLOAD = PREF_CHECK_REGIONS + BEFORE_UPLOAD;
 
     /**
@@ -176,4 +187,5 @@
     protected boolean checkFixmes;
     protected boolean checkPresetsTypes;
+    protected boolean checkRegions;
 
     protected JCheckBox prefCheckKeys;
@@ -182,4 +194,5 @@
     protected JCheckBox prefCheckFixmes;
     protected JCheckBox prefCheckPresetsTypes;
+    protected JCheckBox prefCheckRegions;
 
     protected JCheckBox prefCheckKeysBeforeUpload;
@@ -188,4 +201,5 @@
     protected JCheckBox prefCheckFixmesBeforeUpload;
     protected JCheckBox prefCheckPresetsTypesBeforeUpload;
+    protected JCheckBox prefCheckRegionsBeforeUpload;
 
     // CHECKSTYLE.OFF: SingleSpaceSeparator
@@ -211,4 +225,5 @@
     protected static final int MULTIPOLYGON_MAYBE_NO_AREA       = 1220;
     protected static final int MULTIPOLYGON_SAME_TAG_ON_OUTER   = 1221;
+    protected static final int INVALID_REGION                   = 1222;
     // CHECKSTYLE.ON: SingleSpaceSeparator
 
@@ -560,5 +575,5 @@
      * @return {@code true} if the given key is in internal presets
      * @since 9023
-     * @deprecated Use {@link TaggingPresets#isKeyInPresets(String)} instead
+     * @deprecated since 18281 -- use {@link TaggingPresets#isKeyInPresets(String)} instead
      */
     @Deprecated
@@ -653,40 +668,190 @@
 
         if (p instanceof Relation && p.hasTag("type", "multipolygon")) {
-        checkMultipolygonTags(p);
-        }
-
-        if (checkPresetsTypes) {
-            TagMap tags = p.getKeys();
-            TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);
-            EnumSet<TaggingPresetType> presetTypes = EnumSet.of(presetType);
-
-            Collection<TaggingPreset> matchingPresets = presetIndex.entrySet().stream()
+            checkMultipolygonTags(p);
+        }
+
+        final Collection<TaggingPreset> matchingPresets;
+        TagMap tags;
+        if (checkPresetsTypes || checkRegions) {
+            tags = p.getKeys();
+            matchingPresets = presetIndex.entrySet().stream()
                     .filter(e -> TaggingPresetItem.matches(e.getValue(), tags))
                     .map(Entry::getKey)
                     .collect(Collectors.toCollection(LinkedHashSet::new));
-            Collection<TaggingPreset> matchingPresetsOK = matchingPresets.stream().filter(
-                    tp -> tp.typeMatches(presetTypes)).collect(Collectors.toList());
-            Collection<TaggingPreset> matchingPresetsKO = matchingPresets.stream().filter(
-                    tp -> !tp.typeMatches(presetTypes)).collect(Collectors.toList());
-
-            for (TaggingPreset tp : matchingPresetsKO) {
-                // Potential error, unless matching tags are all known by a supported preset
-                Map<String, String> matchingTags = tp.data.stream()
+        } else {
+            matchingPresets = null;
+            tags = null;
+        }
+
+        if (checkPresetsTypes) {
+            checkPresetsTypes(p, matchingPresets, tags);
+        }
+
+        if (checkRegions) {
+            checkRegions(p, matchingPresets);
+        }
+    }
+
+    /**
+     * Check that the primitive matches the preset types for the preset
+     * @param p The primitive to check
+     * @param matchingPresets The presets to go through
+     * @param tags Tags from the primitive to check
+     */
+    private void checkPresetsTypes(OsmPrimitive p, Collection<TaggingPreset> matchingPresets, Map<String, String> tags) {
+        TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);
+        EnumSet<TaggingPresetType> presetTypes = EnumSet.of(presetType);
+
+        Collection<TaggingPreset> matchingPresetsOK = matchingPresets.stream().filter(
+                tp -> tp.typeMatches(presetTypes)).collect(Collectors.toList());
+        Collection<TaggingPreset> matchingPresetsKO = matchingPresets.stream().filter(
+                tp -> !tp.typeMatches(presetTypes)).collect(Collectors.toList());
+
+        for (TaggingPreset tp : matchingPresetsKO) {
+            // Potential error, unless matching tags are all known by a supported preset
+            Map<String, String> matchingTags = tp.data.stream()
                     .filter(i -> Boolean.TRUE.equals(i.matches(tags)))
                     .filter(i -> i instanceof KeyedItem).map(i -> ((KeyedItem) i).key)
                     .collect(Collectors.toMap(k -> k, tags::get));
-                if (matchingPresetsOK.stream().noneMatch(
-                        tp2 -> matchingTags.entrySet().stream().allMatch(
-                                e -> tp2.data.stream().anyMatch(
-                                        i -> i instanceof KeyedItem && ((KeyedItem) i).key.equals(e.getKey()))))) {
-                    errors.add(TestError.builder(this, Severity.OTHER, INVALID_PRESETS_TYPE)
-                            .message(tr("Object type not in preset"),
-                                    marktr("Object type {0} is not supported by tagging preset: {1}"),
-                                    tr(presetType.getName()), tp.getLocaleName())
+            if (matchingPresetsOK.stream().noneMatch(
+                    tp2 -> matchingTags.entrySet().stream().allMatch(
+                            e -> tp2.data.stream().anyMatch(
+                                    i -> i instanceof KeyedItem && ((KeyedItem) i).key.equals(e.getKey()))))) {
+                errors.add(TestError.builder(this, Severity.OTHER, INVALID_PRESETS_TYPE)
+                        .message(tr("Object type not in preset"),
+                                marktr("Object type {0} is not supported by tagging preset: {1}"),
+                                tr(presetType.getName()), tp.getLocaleName())
+                        .primitives(p)
+                        .build());
+            }
+        }
+    }
+
+    /**
+     * Check that the preset is valid for the region the primitive is in
+     * @param p The primitive to check
+     * @param matchingPresets The presets to check against
+     */
+    private void checkRegions(OsmPrimitive p, Collection<TaggingPreset> matchingPresets) {
+        LatLon center;
+        if (p instanceof Node) {
+            center = ((Node) p).getCoor();
+        } else {
+            center = p.getBBox().getCenter();
+        }
+        for (TaggingPreset preset : matchingPresets) {
+            if (preset.regions() != null) {
+                boolean isInRegion = false; //true if the object is in an applicable region
+                for (String region : preset.regions()) {
+                    if (Territories.isIso3166Code(region, center)) { //check if center of the object is in a region
+                        isInRegion = true;
+                    }
+                }
+                if (isInRegion == preset.exclude_regions()) {
+                    errors.add(TestError.builder(this, Severity.WARNING, INVALID_REGION)
+                            .message(tr("Invalid region for this preset"),
+                                    marktr("Preset {0} should not be applied in this region"),
+                                    preset.getLocaleName())
                             .primitives(p)
                             .build());
                 }
             }
-        }
+            // Check the tags
+            tagCheck(preset, p, center, preset.data);
+        }
+    }
+
+    /**
+     * Perform the checks against a given preset value
+     * @param preset The originating preset (used for error creation)
+     * @param p The originating primitive (used for error creation)
+     * @param center The center of the primitive or other location of the primitive to check
+     * @param tagInformation The sub items for the preset
+     */
+    private void tagCheck(TaggingPreset preset, OsmPrimitive p, LatLon center, List<? extends TaggingPresetItem> tagInformation) {
+        for (TaggingPresetItem item : tagInformation) {
+            if (item instanceof CheckGroup) {
+                tagCheckReal(preset, p, center, ((CheckGroup) item).checks);
+            } else if (item instanceof ComboMultiSelect) {
+                tagCheckReal(preset, p, center, ((ComboMultiSelect) item).presetListEntries());
+            }
+            if (item instanceof RegionSpecific && ((RegionSpecific) item).regions() != null) {
+                tagCheckReal(preset, p, center, (RegionSpecific) item);
+            }
+        }
+    }
+
+    /**
+     * Perform the checks against a given preset value
+     * @param preset The originating preset (used for error creation)
+     * @param p The originating primitive (used for error creation)
+     * @param center The center of the primitive or other location of the primitive to check
+     * @param data The data for the region specific information
+     */
+    private void tagCheckReal(TaggingPreset preset, OsmPrimitive p, LatLon center, List<? extends RegionSpecific> data) {
+        for (RegionSpecific regionSpecific : data) {
+            if (regionSpecific.regions() != null) {
+                tagCheckReal(preset, p, center, regionSpecific);
+            }
+        }
+    }
+
+    /**
+     * Perform the checks against a given preset value
+     * @param preset The originating preset (used for error creation)
+     * @param p The originating primitive (used for error creation)
+     * @param center The center of the primitive or other location of the primitive to check
+     * @param data The data for the region specific information
+     */
+    private void tagCheckReal(TaggingPreset preset, OsmPrimitive p, LatLon center, RegionSpecific data) {
+        // First, check if we aren't in the region for the tag
+        if (latLonInRegions(center, data.regions()) == data.exclude_regions()) {
+            final String key;
+            final String value;
+            if (data instanceof PresetListEntry) {
+                key = ((PresetListEntry) data).cms.key;
+                value = ((PresetListEntry) data).value;
+            } else if (data instanceof KeyedItem) {
+                key = ((KeyedItem) data).key;
+                if (data instanceof Key) {
+                    value = ((Key) data).value;
+                } else {
+                    value = null;
+                }
+            } else {
+                throw new JosmRuntimeException("Unknown implementor for RegionSpecific");
+            }
+            if (p.hasTag(key) && (value == null || value.equals(p.get(key)))) {
+                final TestError.Builder builder = TestError.builder(this, Severity.WARNING, INVALID_REGION)
+                        .primitives(p);
+                if (value == null) {
+                    builder.message(tr("Invalid region for this preset"),
+                            marktr("Preset {0} should not have the key {1}"),
+                            preset.getLocaleName(), key);
+                } else {
+                    builder.message(tr("Invalid region for this preset"),
+                            marktr("Preset {0} should not have the tag {1}={2}"),
+                            preset.getLocaleName(), key, value);
+                }
+                errors.add(builder.build());
+            }
+        }
+    }
+
+    /**
+     * Check if the specified latlon is inside any of the specified regions
+     * @param latLon The {@link LatLon} to check
+     * @param regions The regions to see if the {@link LatLon} is in
+     * @return {@code true} if the coordinate is inside any of the regions
+     */
+    private static boolean latLonInRegions(LatLon latLon, Collection<String> regions) {
+        if (regions != null) {
+            for (String region : regions) {
+                if (Territories.isIso3166Code(region, latLon)) {
+                    return true;
+                }
+            }
+        }
+        return false;
     }
 
@@ -916,5 +1081,5 @@
         }
 
-        if (!Utils.isEmpty(fixedKey) && !fixedKey.equals(key)) {
+        if (!Utils.isEmpty(fixedKey) && !Objects.equals(fixedKey, key)) {
             final String proposedKey = fixedKey;
             // misspelled preset key
@@ -1101,4 +1266,9 @@
             checkPresetsTypes = checkPresetsTypes && Config.getPref().getBoolean(PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD, true);
         }
+
+        checkRegions = includeOtherSeverity && Config.getPref().getBoolean(PREF_CHECK_REGIONS, true);
+        if (isBeforeUpload) {
+            checkRegions = checkRegions && Config.getPref().getBoolean(PREF_CHECK_REGIONS_BEFORE_UPLOAD, true);
+        }
         deprecatedChecker = OsmValidator.getTest(MapCSSTagChecker.class);
         ignoreForOuterMPSameTagCheck.addAll(Config.getPref().getList(PREF_KEYS_IGNORE_OUTER_MP_SAME_TAG, Collections.emptyList()));
@@ -1113,5 +1283,5 @@
     @Override
     public void visit(Collection<OsmPrimitive> selection) {
-        if (checkKeys || checkValues || checkComplex || checkFixmes || checkPresetsTypes) {
+        if (checkKeys || checkValues || checkComplex || checkFixmes || checkPresetsTypes || checkRegions) {
             super.visit(selection);
         }
@@ -1178,4 +1348,12 @@
         prefCheckPresetsTypesBeforeUpload.setSelected(Config.getPref().getBoolean(PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD, true));
         testPanel.add(prefCheckPresetsTypesBeforeUpload, a);
+
+        prefCheckRegions = new JCheckBox(tr("Check for regions."), Config.getPref().getBoolean(PREF_CHECK_REGIONS, true));
+        prefCheckRegions.setToolTipText(tr("Validate that objects are in the correct region."));
+        testPanel.add(prefCheckRegions, GBC.std().insets(20, 0, 0, 0));
+
+        prefCheckRegionsBeforeUpload = new JCheckBox();
+        prefCheckRegionsBeforeUpload.setSelected(Config.getPref().getBoolean(PREF_CHECK_REGIONS_BEFORE_UPLOAD, true));
+        testPanel.add(prefCheckRegionsBeforeUpload, a);
     }
 
@@ -1200,4 +1378,5 @@
         Config.getPref().putBoolean(PREF_CHECK_FIXMES, prefCheckFixmes.isSelected());
         Config.getPref().putBoolean(PREF_CHECK_PRESETS_TYPES, prefCheckPresetsTypes.isSelected());
+        Config.getPref().putBoolean(PREF_CHECK_REGIONS, prefCheckRegions.isSelected());
         Config.getPref().putBoolean(PREF_CHECK_VALUES_BEFORE_UPLOAD, prefCheckValuesBeforeUpload.isSelected());
         Config.getPref().putBoolean(PREF_CHECK_COMPLEX_BEFORE_UPLOAD, prefCheckComplexBeforeUpload.isSelected());
@@ -1205,4 +1384,5 @@
         Config.getPref().putBoolean(PREF_CHECK_FIXMES_BEFORE_UPLOAD, prefCheckFixmesBeforeUpload.isSelected());
         Config.getPref().putBoolean(PREF_CHECK_PRESETS_TYPES_BEFORE_UPLOAD, prefCheckPresetsTypesBeforeUpload.isSelected());
+        Config.getPref().putBoolean(PREF_CHECK_REGIONS_BEFORE_UPLOAD, prefCheckRegionsBeforeUpload.isSelected());
         return Config.getPref().putList(PREF_SOURCES, sourcesList.getItems());
     }
Index: trunk/src/org/openstreetmap/josm/gui/NoteInputDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/NoteInputDialog.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/NoteInputDialog.java	(revision 18918)
@@ -53,5 +53,5 @@
      * @param icon Icon to display in the action button
      * @param text Default text of the note's comment
-     * @since xxx
+     * @since 18839
      */
     public void showNoteDialog(String message, Icon icon, String text) {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java	(revision 18918)
@@ -285,5 +285,5 @@
      * @param selector The selector to use
      * @return A clone of this environment, with the specified selector
-     * @since xxx
+     * @since 18757
      */
     public Environment withSelector(Selector selector) {
@@ -335,5 +335,5 @@
      * Get the selector for this environment
      * @return The selector. May be {@code null}.
-     * @since xxx
+     * @since 18757
      */
     public Selector selector() {
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/PlaceholderExpression.java	(revision 18918)
@@ -15,5 +15,5 @@
 /**
  * Used for expressions that contain placeholders
- * @since xxx
+ * @since 18758
  */
 public final class PlaceholderExpression implements Expression {
Index: trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java	(revision 18918)
@@ -80,5 +80,5 @@
      * @param parameters the OAuth parameters. Must not be null.
      * @param accessToken the Access Token. Must not be null.
-     * @since xxx
+     * @since 18764
      */
     public TestAccessTokenTask(Component parent, String apiUrl, IOAuthParameters parameters, IOAuthToken accessToken) {
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPreset.java	(revision 18918)
@@ -68,4 +68,5 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.Roles;
 import org.openstreetmap.josm.gui.tagging.presets.items.Space;
+import org.openstreetmap.josm.gui.tagging.presets.items.RegionSpecific;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.GBC;
@@ -89,5 +90,6 @@
  * @since 294
  */
-public class TaggingPreset extends AbstractAction implements ActiveLayerChangeListener, AdaptableAction, Predicate<IPrimitive> {
+public class TaggingPreset extends AbstractAction implements ActiveLayerChangeListener, AdaptableAction, Predicate<IPrimitive>,
+        RegionSpecific {
 
     /** The user pressed the "Apply" button */
@@ -142,4 +144,12 @@
      */
     public transient Set<TaggingPresetType> types;
+    /**
+     * List of regions the preset is applicable for.
+     */
+    private Collection<String> regions;
+    /**
+     * If true, invert the meaning of regions.
+     */
+    private boolean excludeRegions;
     /**
      * The list of preset items
@@ -350,4 +360,24 @@
     }
 
+    @Override
+    public final Collection<String> regions() {
+        return this.regions != null || this.group == null ? this.regions : this.group.regions();
+    }
+
+    @Override
+    public final void realSetRegions(Collection<String> regions) {
+        this.regions = regions;
+    }
+
+    @Override
+    public final boolean exclude_regions() {
+        return this.excludeRegions;
+    }
+
+    @Override
+    public final void setExclude_regions(boolean excludeRegions) {
+        this.excludeRegions = excludeRegions;
+    }
+
     private static class PresetPanel extends JPanel {
         private boolean hasElements;
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidation.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidation.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetValidation.java	(revision 18918)
@@ -25,5 +25,7 @@
 import org.openstreetmap.josm.data.validation.tests.MapCSSTagChecker;
 import org.openstreetmap.josm.data.validation.tests.OpeningHourTest;
+import org.openstreetmap.josm.data.validation.tests.TagChecker;
 import org.openstreetmap.josm.gui.MainApplication;
+import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.util.GuiHelper;
 import org.openstreetmap.josm.tools.Logging;
@@ -56,9 +58,14 @@
             MapCSSTagChecker mapCSSTagChecker = OsmValidator.getTest(MapCSSTagChecker.class);
             OpeningHourTest openingHourTest = OsmValidator.getTest(OpeningHourTest.class);
-            OsmValidator.initializeTests(Arrays.asList(mapCSSTagChecker, openingHourTest));
+            TagChecker tagChecker = OsmValidator.getTest(TagChecker.class);
+            tagChecker.startTest(NullProgressMonitor.INSTANCE); //since initializeTest works if test is enabled
+            OsmValidator.initializeTests(Arrays.asList(mapCSSTagChecker, openingHourTest, tagChecker));
+
 
             List<TestError> errors = new ArrayList<>();
             openingHourTest.addErrorsForPrimitive(primitive, errors);
             errors.addAll(mapCSSTagChecker.getErrorsForPrimitive(primitive, ValidatorPrefHelper.PREF_OTHER.get()));
+            tagChecker.check(primitive);
+            errors.addAll(tagChecker.getErrors());
 
             boolean visible = !errors.isEmpty();
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/ComboMultiSelect.java	(revision 18918)
@@ -11,4 +11,5 @@
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -310,5 +311,5 @@
         }
 
-        if (values_sort && TaggingPresets.SORT_MENU.get()) {
+        if (values_sort && Boolean.TRUE.equals(TaggingPresets.SORT_MENU.get())) {
             presetListEntries.sort((a, b) -> AlphanumComparator.getInstance().compare(a.getDisplayValue(), b.getDisplayValue()));
         }
@@ -341,5 +342,5 @@
             initialValue = DIFFERENT;
             originalValue = initialValue;
-        } else if (!usage.hadKeys() || isForceUseLastAsDefault() || PROP_FILL_DEFAULT.get()) {
+        } else if (!usage.hadKeys() || isForceUseLastAsDefault() || Boolean.TRUE.equals(PROP_FILL_DEFAULT.get())) {
             // at this point no primitive had any value for this key
             if (!support.isPresetInitiallyMatches() && isUseLastAsDefault() && LAST_VALUES.containsKey(key)) {
@@ -404,4 +405,12 @@
 
     /**
+     * Get the entries for this {@link ComboMultiSelect} object
+     * @return The {@link PresetListEntry} values for this object
+     */
+    public List<PresetListEntry> presetListEntries() {
+        return Collections.unmodifiableList(this.presetListEntries);
+    }
+
+    /**
      * Adds a preset list entry.
      * @param e list entry to add
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java	(revision 18918)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.tagging.presets.items;
 
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -8,6 +9,6 @@
 import java.util.HashMap;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.SortedMap;
-import java.util.NoSuchElementException;
 import java.util.TreeMap;
 
@@ -25,10 +26,10 @@
  * Preset item associated to an OSM key.
  */
-public abstract class KeyedItem extends TextItem {
+public abstract class KeyedItem extends TextItem implements RegionSpecific {
 
     /** The constant value {@code "<different>"}. */
-    protected static final String DIFFERENT = "<different>";
+    protected static final String DIFFERENT = marktr("<different>");
     /** Translation of {@code "<different>"}. */
-    public static final String DIFFERENT_I18N = tr("<different>");
+    public static final String DIFFERENT_I18N = tr(DIFFERENT);
 
     /** True if the default value should also be set on primitives that already have tags.  */
@@ -52,4 +53,13 @@
      */
     public String match = getDefaultMatch().getValue(); // NOSONAR
+
+    /**
+     * List of regions the preset is applicable for.
+     */
+    private Collection<String> regions;
+    /**
+     * If true, invert the meaning of regions.
+     */
+    private boolean excludeRegions;
 
     /**
@@ -262,4 +272,24 @@
 
     @Override
+    public final Collection<String> regions() {
+        return this.regions;
+    }
+
+    @Override
+    public final void realSetRegions(Collection<String> regions) {
+        this.regions = regions;
+    }
+
+    @Override
+    public final boolean exclude_regions() {
+        return this.excludeRegions;
+    }
+
+    @Override
+    public final void setExclude_regions(boolean excludeRegions) {
+        this.excludeRegions = excludeRegions;
+    }
+
+    @Override
     public String toString() {
         return "KeyedItem [key=" + key + ", text=" + text
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/PresetListEntry.java	(revision 18918)
@@ -6,4 +6,5 @@
 import static org.openstreetmap.josm.tools.I18n.trc;
 
+import java.util.Collection;
 import java.util.Objects;
 
@@ -21,5 +22,5 @@
  * {@link MultiSelect}.
  */
-public class PresetListEntry implements Comparable<PresetListEntry> {
+public class PresetListEntry implements Comparable<PresetListEntry>, RegionSpecific {
     /** Used to display an entry matching several different values. */
     protected static final PresetListEntry ENTRY_DIFFERENT = new PresetListEntry(KeyedItem.DIFFERENT, null);
@@ -48,4 +49,14 @@
     public String locale_short_description; // NOSONAR
 
+    /**
+     * List of regions the entry is applicable for.
+     */
+    private Collection<String> regions;
+
+    /**
+     * If true, invert the meaning of regions.
+     */
+    private boolean excludeRegions;
+
     private String cachedDisplayValue;
     private String cachedShortDescription;
@@ -54,5 +65,5 @@
     /**
      * Constructs a new {@code PresetListEntry}, uninitialized.
-     *
+     * <p>
      * Public default constructor is needed by {@link org.openstreetmap.josm.tools.XmlObjectParser.Parser#startElement}
      */
@@ -74,5 +85,5 @@
     /**
      * Returns the contents displayed in the dropdown list.
-     *
+     * <p>
      * This is the contents that would be displayed in the current view plus a short description to
      * aid the user. The whole content is wrapped to {@code width}.
@@ -164,4 +175,24 @@
     }
 
+    @Override
+    public Collection<String> regions() {
+        return this.regions;
+    }
+
+    @Override
+    public void realSetRegions(Collection<String> regions) {
+        this.regions = regions;
+    }
+
+    @Override
+    public boolean exclude_regions() {
+        return this.excludeRegions;
+    }
+
+    @Override
+    public void setExclude_regions(boolean excludeRegions) {
+        this.excludeRegions = excludeRegions;
+    }
+
     // toString is mainly used to initialize the Editor
     @Override
Index: trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/RegionSpecific.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/RegionSpecific.java	(revision 18918)
+++ trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/RegionSpecific.java	(revision 18918)
@@ -0,0 +1,62 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.tagging.presets.items;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.openstreetmap.josm.tools.Territories;
+import org.openstreetmap.josm.tools.Utils;
+import org.xml.sax.SAXException;
+
+/**
+ * Indicates that this object may be specific to a region
+ * @since 18918
+ */
+public interface RegionSpecific {
+    /**
+     * Get the regions for the item
+     * @return The regions that the item is valid for
+     * @apiNote This is not {@code getRegions} just in case we decide to make the {@link RegionSpecific} record classes.
+     */
+    Collection<String> regions();
+
+    /**
+     * Set the regions for the preset
+     * @param regions The region list (comma delimited)
+     * @throws SAXException if an unknown ISO 3166-2 is found
+     */
+    default void setRegions(String regions) throws SAXException {
+        Set<String> regionSet = Collections.unmodifiableSet(Arrays.stream(regions.split(","))
+                .map(Utils::intern).collect(Collectors.toSet()));
+        for (String region : regionSet) {
+            if (!Territories.getKnownIso3166Codes().contains(region)) {
+                throw new SAXException(tr("Unknown ISO-3166 Code: {0}", region));
+            }
+        }
+        this.realSetRegions(regionSet);
+    }
+
+    /**
+     * Set the regions for the preset
+     * @param regions The region collection
+     */
+    void realSetRegions(Collection<String> regions);
+
+    /**
+     * Get the exclude_regions for the preset
+     * @apiNote This is not {@code getExclude_regions} just in case we decide to make {@link RegionSpecific} a record class.
+     * @return {@code true} if the meaning of {@link #regions()} should be inverted
+     */
+    boolean exclude_regions();
+
+    /**
+     * Set if the preset should not be used in the given region
+     * @param excludeRegions if true the function of regions is inverted
+     */
+    void setExclude_regions(boolean excludeRegions);
+}
Index: trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 18915)
+++ trunk/src/org/openstreetmap/josm/io/imagery/WMSImagery.java	(revision 18918)
@@ -165,5 +165,5 @@
      * @throws WMSGetCapabilitiesException when there are errors when parsing get capabilities document
      * @throws InvalidPathException if a Path object cannot be constructed for the capabilities cached file
-     * @since xxx
+     * @since 18780
      */
     public WMSImagery(String url, Map<String, String> headers, ProgressMonitor monitor)
