Changeset 16545 in josm for trunk/src/org
- Timestamp:
- 2020-06-07T10:12:42+02:00 (4 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 7 added
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/StructUtils.java
r16436 r16545 152 152 153 153 HashMap<String, String> hash = new LinkedHashMap<>(); 154 for (Field f : klass.getDeclaredFields()) {154 for (Field f : getDeclaredFieldsInClassOrSuperTypes(klass)) { 155 155 if (f.getAnnotation(StructEntry.class) == null) { 156 156 continue; … … 201 201 for (Map.Entry<String, String> keyValue : hash.entrySet()) { 202 202 Object value; 203 Field f; 204 try { 205 f = klass.getDeclaredField(keyValue.getKey().replace('-', '_')); 206 } catch (NoSuchFieldException ex) { 207 Logging.trace(ex); 208 continue; 209 } 210 if (f.getAnnotation(StructEntry.class) == null) { 203 Field f = getDeclaredFieldInClassOrSuperTypes(klass, keyValue.getKey().replace('-', '_')); 204 205 if (f == null || f.getAnnotation(StructEntry.class) == null) { 211 206 continue; 212 207 } … … 244 239 } 245 240 return struct; 241 } 242 243 private static <T> Field getDeclaredFieldInClassOrSuperTypes(Class<T> clazz, String fieldName) { 244 Class<?> tClass = clazz; 245 do { 246 try { 247 return tClass.getDeclaredField(fieldName); 248 } catch (NoSuchFieldException ex) { 249 Logging.trace(ex); 250 } 251 tClass = tClass.getSuperclass(); 252 } while (tClass != null); 253 return null; 254 } 255 256 private static <T> Field[] getDeclaredFieldsInClassOrSuperTypes(Class<T> clazz) { 257 List<Field> fields = new ArrayList<>(); 258 Class<?> tclass = clazz; 259 do { 260 Collections.addAll(fields, tclass.getDeclaredFields()); 261 tclass = tclass.getSuperclass(); 262 } while (tclass != null); 263 return fields.toArray(new Field[] {}); 246 264 } 247 265 -
trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
r16436 r16545 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.Image;7 6 import java.io.StringReader; 8 7 import java.util.ArrayList; … … 11 10 import java.util.Collections; 12 11 import java.util.EnumMap; 13 import java.util.HashMap;14 12 import java.util.List; 15 13 import java.util.Locale; … … 17 15 import java.util.Objects; 18 16 import java.util.Optional; 19 import java.util.Set;20 import java.util.TreeSet;21 17 import java.util.concurrent.TimeUnit; 22 18 import java.util.regex.Matcher; … … 27 23 import javax.json.JsonObject; 28 24 import javax.json.JsonReader; 29 import javax.json.stream.JsonCollectors;30 25 import javax.swing.ImageIcon; 31 26 32 import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;33 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;34 import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;35 import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;36 import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;37 import org.openstreetmap.josm.data.Bounds;38 import org.openstreetmap.josm.data.StructUtils;39 27 import org.openstreetmap.josm.data.StructUtils.StructEntry; 40 import org.openstreetmap.josm.io.Capabilities; 41 import org.openstreetmap.josm.io.OsmApi; 42 import org.openstreetmap.josm.spi.preferences.Config; 43 import org.openstreetmap.josm.spi.preferences.IPreferences; 28 import org.openstreetmap.josm.data.sources.ISourceCategory; 29 import org.openstreetmap.josm.data.sources.ISourceType; 30 import org.openstreetmap.josm.data.sources.SourceBounds; 31 import org.openstreetmap.josm.data.sources.SourceInfo; 32 import org.openstreetmap.josm.data.sources.SourcePreferenceEntry; 44 33 import org.openstreetmap.josm.tools.CheckParameterUtil; 45 34 import org.openstreetmap.josm.tools.ImageProvider; 46 35 import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 47 import org.openstreetmap.josm.tools.LanguageInfo;48 36 import org.openstreetmap.josm.tools.Logging; 49 37 import org.openstreetmap.josm.tools.MultiMap; … … 56 44 * @author Frederik Ramm 57 45 */ 58 public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInfo>, Attributed { 46 public class ImageryInfo extends 47 SourceInfo<ImageryInfo.ImageryCategory, ImageryInfo.ImageryType, ImageryInfo.ImageryBounds, ImageryInfo.ImageryPreferenceEntry> { 59 48 60 49 /** 61 50 * Type of imagery entry. 62 51 */ 63 public enum ImageryType {52 public enum ImageryType implements ISourceType<ImageryType> { 64 53 /** A WMS (Web Map Service) entry. **/ 65 54 WMS("wms"), … … 86 75 * @since 6690 87 76 */ 77 @Override 88 78 public final String getTypeString() { 89 79 return typeString; … … 100 90 .findFirst().orElse(null); 101 91 } 92 93 @Override 94 public ImageryType getFromString(String s) { 95 return fromString(s); 96 } 97 98 @Override 99 public ImageryType getDefault() { 100 return WMS; 101 } 102 102 } 103 103 … … 106 106 * @since 13792 107 107 */ 108 public enum ImageryCategory {108 public enum ImageryCategory implements ISourceCategory<ImageryCategory> { 109 109 /** A aerial or satellite photo. **/ 110 110 PHOTO(/* ICON(data/imagery/) */ "photo", tr("Aerial or satellite photo")), … … 138 138 * @return the unique string identifying this category 139 139 */ 140 @Override 140 141 public final String getCategoryString() { 141 142 return category; … … 146 147 * @return the description of this category 147 148 */ 149 @Override 148 150 public final String getDescription() { 149 151 return description; … … 156 158 * @since 15049 157 159 */ 160 @Override 158 161 public final ImageIcon getIcon(ImageSizes size) { 159 162 return iconCache … … 172 175 .findFirst().orElse(null); 173 176 } 177 178 @Override 179 public ImageryCategory getDefault() { 180 return OTHER; 181 } 182 183 @Override 184 public ImageryCategory getFromString(String s) { 185 return fromString(s); 186 } 174 187 } 175 188 … … 178 191 * Used to display imagery coverage in preferences and to determine relevant imagery entries based on edit location. 179 192 */ 180 public static class ImageryBounds extends Bounds {193 public static class ImageryBounds extends SourceBounds { 181 194 182 195 /** … … 188 201 super(asString, separator); 189 202 } 190 191 private List<Shape> shapes = new ArrayList<>(); 192 193 /** 194 * Adds a new shape to this bounds. 195 * @param shape The shape to add 196 */ 197 public final void addShape(Shape shape) { 198 this.shapes.add(shape); 199 } 200 201 /** 202 * Sets the list of shapes defining this bounds. 203 * @param shapes The list of shapes defining this bounds. 204 */ 205 public final void setShapes(List<Shape> shapes) { 206 this.shapes = shapes; 207 } 208 209 /** 210 * Returns the list of shapes defining this bounds. 211 * @return The list of shapes defining this bounds 212 */ 213 public final List<Shape> getShapes() { 214 return shapes; 215 } 216 217 @Override 218 public int hashCode() { 219 return Objects.hash(super.hashCode(), shapes); 220 } 221 222 @Override 223 public boolean equals(Object o) { 224 if (this == o) return true; 225 if (o == null || getClass() != o.getClass()) return false; 226 if (!super.equals(o)) return false; 227 ImageryBounds that = (ImageryBounds) o; 228 return Objects.equals(shapes, that.shapes); 229 } 230 } 231 232 /** original name of the imagery entry in case of translation call, for multiple languages English when possible */ 233 private String origName; 234 /** (original) language of the translated name entry */ 235 private String langName; 236 /** whether this is a entry activated by default or not */ 237 private boolean defaultEntry; 238 /** Whether this service requires a explicit EULA acceptance before it can be activated */ 239 private String eulaAcceptanceRequired; 240 /** type of the imagery servics - WMS, TMS, ... */ 241 private ImageryType imageryType = ImageryType.WMS; 203 } 204 242 205 private double pixelPerDegree; 243 206 /** maximum zoom level for TMS imagery */ … … 245 208 /** minimum zoom level for TMS imagery */ 246 209 private int defaultMinZoom; 247 /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */248 private ImageryBounds bounds;249 210 /** projections supported by WMS servers */ 250 211 private List<String> serverProjections = Collections.emptyList(); 251 /** description of the imagery entry, should contain notes what type of data it is */252 private String description;253 /** language of the description entry */254 private String langDescription;255 /** Text of a text attribution displayed when using the imagery */256 private String attributionText;257 /** Link to the privacy policy of the operator */258 private String privacyPolicyURL;259 /** Link to a reference stating the permission for OSM usage */260 private String permissionReferenceURL;261 /** Link behind the text attribution displayed when using the imagery */262 private String attributionLinkURL;263 /** Image of a graphical attribution displayed when using the imagery */264 private String attributionImage;265 /** Link behind the graphical attribution displayed when using the imagery */266 private String attributionImageURL;267 /** Text with usage terms displayed when using the imagery */268 private String termsOfUseText;269 /** Link behind the text with usage terms displayed when using the imagery */270 private String termsOfUseURL;271 /** country code of the imagery (for country specific imagery) */272 private String countryCode = "";273 /**274 * creation date of the imagery (in the form YYYY-MM-DD;YYYY-MM-DD, where275 * DD and MM as well as a second date are optional).276 *277 * Also used as time filter for WMS time={time} parameter (such as Sentinel-2)278 * @since 11570279 */280 private String date;281 212 /** 282 213 * marked as best in other editors … … 289 220 */ 290 221 private boolean overlay; 291 /** 292 * list of old IDs, only for loading, not handled anywhere else 293 * @since 13536 294 */ 295 private Collection<String> oldIds; 222 296 223 /** mirrors of different type for this entry */ 297 private List<ImageryInfo> mirrors; 298 /** icon used in menu */ 299 private String icon; 224 protected List<ImageryInfo> mirrors; 225 /** 226 * Auxiliary class to save an {@link ImageryInfo} object in the preferences. 227 */ 300 228 /** is the geo reference correct - don't offer offset handling */ 301 229 private boolean isGeoreferenceValid; 302 /** which layers should be activated by default on layer addition. **/303 private List<DefaultLayer> defaultLayers = Collections.emptyList();304 /** HTTP headers **/305 private Map<String, String> customHttpHeaders = Collections.emptyMap();306 230 /** Should this map be transparent **/ 307 231 private boolean transparent = true; 308 232 private int minimumTileExpire = (int) TimeUnit.MILLISECONDS.toSeconds(TMSCachedTileLoaderJob.MINIMUM_EXPIRES.get()); 309 /** category of the imagery */ 310 private ImageryCategory category; 311 /** category of the imagery (input string, not saved, copied or used otherwise except for error checks) */ 312 private String categoryOriginalString; 313 /** when adding a field, also adapt the: 314 * {@link #ImageryPreferenceEntry ImageryPreferenceEntry object} 315 * {@link #ImageryPreferenceEntry#ImageryPreferenceEntry(ImageryInfo) ImageryPreferenceEntry constructor} 316 * {@link #ImageryInfo(ImageryPreferenceEntry) ImageryInfo constructor} 317 * {@link #ImageryInfo(ImageryInfo) ImageryInfo constructor} 318 * {@link #equalsPref(ImageryPreferenceEntry) equalsPref method} 319 **/ 320 321 /** 322 * Auxiliary class to save an {@link ImageryInfo} object in the preferences. 323 */ 324 public static class ImageryPreferenceEntry { 325 @StructEntry String name; 233 234 /** 235 * The ImageryPreferenceEntry class for storing data in JOSM preferences. 236 * 237 * @author Frederik Ramm, modified by Taylor Smock 238 */ 239 public static class ImageryPreferenceEntry extends SourcePreferenceEntry<ImageryInfo> { 326 240 @StructEntry String d; 327 @StructEntry String id;328 @StructEntry String type;329 @StructEntry String url;330 241 @StructEntry double pixel_per_eastnorth; 331 @StructEntry String eula;332 @StructEntry String attribution_text;333 @StructEntry String attribution_url;334 @StructEntry String permission_reference_url;335 @StructEntry String logo_image;336 @StructEntry String logo_url;337 @StructEntry String terms_of_use_text;338 @StructEntry String terms_of_use_url;339 @StructEntry String country_code = "";340 @StructEntry String date;341 242 @StructEntry int max_zoom; 342 243 @StructEntry int min_zoom; 343 @StructEntry String cookies;344 @StructEntry String bounds;345 @StructEntry String shapes;346 244 @StructEntry String projections; 347 @StructEntry String icon;348 @StructEntry String description;349 245 @StructEntry MultiMap<String, String> noTileHeaders; 350 246 @StructEntry MultiMap<String, String> noTileChecksums; … … 355 251 @StructEntry boolean modTileFeatures; 356 252 @StructEntry boolean overlay; 357 @StructEntry String default_layers;358 @StructEntry Map<String, String> customHttpHeaders;359 253 @StructEntry boolean transparent; 360 254 @StructEntry int minimumTileExpire; 361 @StructEntry String category;362 255 363 256 /** … … 365 258 */ 366 259 public ImageryPreferenceEntry() { 367 // Do nothing260 super(); 368 261 } 369 262 … … 373 266 */ 374 267 public ImageryPreferenceEntry(ImageryInfo i) { 375 name = i.name; 376 id = i.id; 377 type = i.imageryType.getTypeString(); 378 url = i.url; 268 super(i); 379 269 pixel_per_eastnorth = i.pixelPerDegree; 380 eula = i.eulaAcceptanceRequired;381 attribution_text = i.attributionText;382 attribution_url = i.attributionLinkURL;383 permission_reference_url = i.permissionReferenceURL;384 date = i.date;385 270 bestMarked = i.bestMarked; 386 271 overlay = i.overlay; 387 logo_image = i.attributionImage;388 logo_url = i.attributionImageURL;389 terms_of_use_text = i.termsOfUseText;390 terms_of_use_url = i.termsOfUseURL;391 country_code = i.countryCode;392 272 max_zoom = i.defaultMaxZoom; 393 273 min_zoom = i.defaultMinZoom; 394 cookies = i.cookies;395 icon = intern(i.icon);396 description = i.description;397 category = i.category != null ? i.category.getCategoryString() : null;398 if (i.bounds != null) {399 bounds = i.bounds.encodeAsString(",");400 String shapesString = Shape.encodeAsString(i.bounds.getShapes());401 if (!shapesString.isEmpty()) {402 shapes = shapesString;403 }404 }405 274 if (!i.serverProjections.isEmpty()) { 406 275 projections = String.join(",", i.serverProjections); … … 422 291 valid_georeference = i.isGeoreferenceValid(); 423 292 modTileFeatures = i.isModTileFeatures(); 424 if (!i.defaultLayers.isEmpty()) {425 default_layers = i.defaultLayers.stream().map(DefaultLayer::toJson).collect(JsonCollectors.toJsonArray()).toString();426 }427 customHttpHeaders = i.customHttpHeaders;428 293 transparent = i.isTransparent(); 429 294 minimumTileExpire = i.minimumTileExpire; … … 494 359 this.eulaAcceptanceRequired = eulaAcceptanceRequired; 495 360 if (t != null) { 496 this. imageryType = t;361 this.sourceType = t; 497 362 } else if (type != null && !type.isEmpty()) { 498 363 throw new IllegalArgumentException("unknown type: "+type); … … 526 391 cookies = e.cookies; 527 392 eulaAcceptanceRequired = e.eula; 528 imageryType = ImageryType.fromString(e.type);529 if ( imageryType == null) throw new IllegalArgumentException("unknown type");393 sourceType = ImageryType.fromString(e.type); 394 if (sourceType == null) throw new IllegalArgumentException("unknown type"); 530 395 pixelPerDegree = e.pixel_per_eastnorth; 531 396 defaultMaxZoom = e.max_zoom; … … 547 412 setServerProjections(Arrays.asList(e.projections.split(","))); 548 413 } 549 attributionText = intern(e.attribution_text);414 attributionText = Utils.intern(e.attribution_text); 550 415 attributionLinkURL = e.attribution_url; 551 416 permissionReferenceURL = e.permission_reference_url; … … 557 422 termsOfUseText = e.terms_of_use_text; 558 423 termsOfUseURL = e.terms_of_use_url; 559 countryCode = intern(e.country_code);560 icon = intern(e.icon);424 countryCode = Utils.intern(e.country_code); 425 icon = Utils.intern(e.icon); 561 426 if (e.noTileHeaders != null) { 562 427 noTileHeaders = e.noTileHeaders.toMap(); … … 574 439 readArray(). 575 440 stream(). 576 map(x -> DefaultLayer.fromJson((JsonObject) x, imageryType)).441 map(x -> DefaultLayer.fromJson((JsonObject) x, sourceType)). 577 442 collect(Collectors.toList()); 578 443 } … … 603 468 this.defaultEntry = i.defaultEntry; 604 469 this.eulaAcceptanceRequired = null; 605 this. imageryType = i.imageryType;470 this.sourceType = i.sourceType; 606 471 this.pixelPerDegree = i.pixelPerDegree; 607 472 this.defaultMaxZoom = i.defaultMaxZoom; … … 624 489 this.overlay = i.overlay; 625 490 // do not copy field {@code mirrors} 626 this.icon = intern(i.icon);491 this.icon = Utils.intern(i.icon); 627 492 this.isGeoreferenceValid = i.isGeoreferenceValid; 628 493 setDefaultLayers(i.defaultLayers); … … 630 495 this.transparent = i.transparent; 631 496 this.minimumTileExpire = i.minimumTileExpire; 632 this.categoryOriginalString = intern(i.categoryOriginalString);497 this.categoryOriginalString = Utils.intern(i.categoryOriginalString); 633 498 this.category = i.category; 634 499 } 635 500 636 @Override 637 public int hashCode() { 638 return Objects.hash(url, imageryType); 501 /** 502 * Adds a mirror entry. Mirror entries are completed with the data from the master entry 503 * and only describe another method to access identical data. 504 * 505 * @param entry the mirror to be added 506 * @since 9658 507 */ 508 public void addMirror(ImageryInfo entry) { 509 if (mirrors == null) { 510 mirrors = new ArrayList<>(); 511 } 512 mirrors.add(entry); 513 } 514 515 /** 516 * Returns the mirror entries. Entries are completed with master entry data. 517 * 518 * @return the list of mirrors 519 * @since 9658 520 */ 521 public List<ImageryInfo> getMirrors() { 522 List<ImageryInfo> l = new ArrayList<>(); 523 if (mirrors != null) { 524 int num = 1; 525 for (ImageryInfo i : mirrors) { 526 ImageryInfo n = new ImageryInfo(this); 527 if (i.defaultMaxZoom != 0) { 528 n.defaultMaxZoom = i.defaultMaxZoom; 529 } 530 if (i.defaultMinZoom != 0) { 531 n.defaultMinZoom = i.defaultMinZoom; 532 } 533 n.setServerProjections(i.getServerProjections()); 534 n.url = i.url; 535 n.sourceType = i.sourceType; 536 if (i.getTileSize() != 0) { 537 n.setTileSize(i.getTileSize()); 538 } 539 if (i.getPrivacyPolicyURL() != null) { 540 n.setPrivacyPolicyURL(i.getPrivacyPolicyURL()); 541 } 542 if (n.id != null) { 543 n.id = n.id + "_mirror" + num; 544 } 545 if (num > 1) { 546 n.name = tr("{0} mirror server {1}", n.name, num); 547 if (n.origName != null) { 548 n.origName += " mirror server " + num; 549 } 550 } else { 551 n.name = tr("{0} mirror server", n.name); 552 if (n.origName != null) { 553 n.origName += " mirror server"; 554 } 555 } 556 l.add(n); 557 ++num; 558 } 559 } 560 return l; 639 561 } 640 562 … … 648 570 * @return true if they are equal 649 571 */ 650 public boolean equalsPref(ImageryInfo other) { 651 if (other == null) { 572 @Override 573 public boolean equalsPref(SourceInfo<ImageryInfo.ImageryCategory, ImageryInfo.ImageryType, 574 ImageryInfo.ImageryBounds, ImageryInfo.ImageryPreferenceEntry> other) { 575 if (!(other instanceof ImageryInfo)) { 652 576 return false; 653 577 } 578 ImageryInfo realOther = (ImageryInfo) other; 654 579 655 580 // CHECKSTYLE.OFF: BooleanExpressionComplexity 656 return 657 Objects.equals(this.name, other.name) && 658 Objects.equals(this.id, other.id) && 659 Objects.equals(this.url, other.url) && 660 Objects.equals(this.modTileFeatures, other.modTileFeatures) && 661 Objects.equals(this.bestMarked, other.bestMarked) && 662 Objects.equals(this.overlay, other.overlay) && 663 Objects.equals(this.isGeoreferenceValid, other.isGeoreferenceValid) && 664 Objects.equals(this.cookies, other.cookies) && 665 Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) && 666 Objects.equals(this.imageryType, other.imageryType) && 667 Objects.equals(this.defaultMaxZoom, other.defaultMaxZoom) && 668 Objects.equals(this.defaultMinZoom, other.defaultMinZoom) && 669 Objects.equals(this.bounds, other.bounds) && 670 Objects.equals(this.serverProjections, other.serverProjections) && 671 Objects.equals(this.attributionText, other.attributionText) && 672 Objects.equals(this.attributionLinkURL, other.attributionLinkURL) && 673 Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) && 674 Objects.equals(this.attributionImageURL, other.attributionImageURL) && 675 Objects.equals(this.attributionImage, other.attributionImage) && 676 Objects.equals(this.termsOfUseText, other.termsOfUseText) && 677 Objects.equals(this.termsOfUseURL, other.termsOfUseURL) && 678 Objects.equals(this.countryCode, other.countryCode) && 679 Objects.equals(this.date, other.date) && 680 Objects.equals(this.icon, other.icon) && 681 Objects.equals(this.description, other.description) && 682 Objects.equals(this.noTileHeaders, other.noTileHeaders) && 683 Objects.equals(this.noTileChecksums, other.noTileChecksums) && 684 Objects.equals(this.metadataHeaders, other.metadataHeaders) && 685 Objects.equals(this.defaultLayers, other.defaultLayers) && 686 Objects.equals(this.customHttpHeaders, other.customHttpHeaders) && 687 Objects.equals(this.transparent, other.transparent) && 688 Objects.equals(this.minimumTileExpire, other.minimumTileExpire) && 689 Objects.equals(this.category, other.category); 581 return super.equalsPref(realOther) && 582 Objects.equals(this.bestMarked, realOther.bestMarked) && 583 Objects.equals(this.overlay, realOther.overlay) && 584 Objects.equals(this.isGeoreferenceValid, realOther.isGeoreferenceValid) && 585 Objects.equals(this.defaultMaxZoom, realOther.defaultMaxZoom) && 586 Objects.equals(this.defaultMinZoom, realOther.defaultMinZoom) && 587 Objects.equals(this.serverProjections, realOther.serverProjections) && 588 Objects.equals(this.transparent, realOther.transparent) && 589 Objects.equals(this.minimumTileExpire, realOther.minimumTileExpire); 690 590 // CHECKSTYLE.ON: BooleanExpressionComplexity 691 591 } 692 592 693 593 @Override 694 public boolean equals(Object o) { 695 if (this == o) return true; 696 if (o == null || getClass() != o.getClass()) return false; 697 ImageryInfo that = (ImageryInfo) o; 698 return imageryType == that.imageryType && Objects.equals(url, that.url); 699 } 700 701 private static final Map<String, String> localizedCountriesCache = new HashMap<>(); 702 static { 703 localizedCountriesCache.put("", tr("Worldwide")); 704 } 705 706 /** 707 * Returns a localized name for the given country code, or "Worldwide" if empty. 708 * This function falls back on the English name, and uses the ISO code as a last-resortvalue. 709 * 710 * @param countryCode An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code 711 * @return The name of the country appropriate to the current locale. 712 * @see Locale#getDisplayCountry 713 * @since 15158 714 */ 715 public static String getLocalizedCountry(String countryCode) { 716 return localizedCountriesCache.computeIfAbsent(countryCode, code -> new Locale("en", code).getDisplayCountry()); 717 } 718 719 @Override 720 public String toString() { 721 // Used in imagery preferences filtering, so must be efficient 722 return new StringBuilder(name) 723 .append('[').append(countryCode) 724 // appending the localized country in toString() allows us to filter imagery preferences table with it! 725 .append("] ('").append(getLocalizedCountry(countryCode)).append(')') 726 .append(" - ").append(url) 727 .append(" - ").append(imageryType) 728 .toString(); 729 } 730 731 @Override 732 public int compareTo(ImageryInfo in) { 733 int i = countryCode.compareTo(in.countryCode); 734 if (i == 0) { 735 i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH)); 736 } 737 if (i == 0) { 738 i = url.compareTo(in.url); 739 } 740 if (i == 0) { 741 i = Double.compare(pixelPerDegree, in.pixelPerDegree); 594 public int compareTo(SourceInfo<ImageryInfo.ImageryCategory, ImageryInfo.ImageryType, 595 ImageryInfo.ImageryBounds, ImageryInfo.ImageryPreferenceEntry> other) { 596 int i = super.compareTo(other); 597 if (other instanceof ImageryInfo) { 598 ImageryInfo in = (ImageryInfo) other; 599 if (i == 0) { 600 i = Double.compare(pixelPerDegree, in.pixelPerDegree); 601 } 742 602 } 743 603 return i; 744 }745 746 /**747 * Determines if URL is equal to given imagery info.748 * @param in imagery info749 * @return {@code true} if URL is equal to given imagery info750 */751 public boolean equalsBaseValues(ImageryInfo in) {752 return url.equals(in.url);753 604 } 754 605 … … 779 630 780 631 /** 781 * Sets the imagery polygonial bounds.782 * @param b The imagery bounds (non-rectangular)783 */784 public void setBounds(ImageryBounds b) {785 this.bounds = b;786 }787 788 /**789 * Returns the imagery polygonial bounds.790 * @return The imagery bounds (non-rectangular)791 */792 public ImageryBounds getBounds() {793 return bounds;794 }795 796 @Override797 public boolean requiresAttribution() {798 return attributionText != null || attributionLinkURL != null || attributionImage != null799 || termsOfUseText != null || termsOfUseURL != null;800 }801 802 @Override803 public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {804 return attributionText;805 }806 807 @Override808 public String getAttributionLinkURL() {809 return attributionLinkURL;810 }811 812 /**813 * Return the permission reference URL.814 * @return The url815 * @see #setPermissionReferenceURL816 * @since 11975817 */818 public String getPermissionReferenceURL() {819 return permissionReferenceURL;820 }821 822 /**823 * Return the privacy policy URL.824 * @return The url825 * @see #setPrivacyPolicyURL826 * @since 16127827 */828 public String getPrivacyPolicyURL() {829 return privacyPolicyURL;830 }831 832 @Override833 public Image getAttributionImage() {834 ImageIcon i = ImageProvider.getIfAvailable(attributionImage);835 if (i != null) {836 return i.getImage();837 }838 return null;839 }840 841 /**842 * Return the raw attribution logo information (an URL to the image).843 * @return The url text844 * @since 12257845 */846 public String getAttributionImageRaw() {847 return attributionImage;848 }849 850 @Override851 public String getAttributionImageURL() {852 return attributionImageURL;853 }854 855 @Override856 public String getTermsOfUseText() {857 return termsOfUseText;858 }859 860 @Override861 public String getTermsOfUseURL() {862 return termsOfUseURL;863 }864 865 /**866 * Set the attribution text867 * @param text The text868 * @see #getAttributionText(int, ICoordinate, ICoordinate)869 */870 public void setAttributionText(String text) {871 attributionText = intern(text);872 }873 874 /**875 * Set the attribution image876 * @param url The url of the image.877 * @see #getAttributionImageURL()878 */879 public void setAttributionImageURL(String url) {880 attributionImageURL = url;881 }882 883 /**884 * Set the image for the attribution885 * @param res The image resource886 * @see #getAttributionImage()887 */888 public void setAttributionImage(String res) {889 attributionImage = res;890 }891 892 /**893 * Sets the URL the attribution should link to.894 * @param url The url.895 * @see #getAttributionLinkURL()896 */897 public void setAttributionLinkURL(String url) {898 attributionLinkURL = url;899 }900 901 /**902 * Sets the permission reference URL.903 * @param url The url.904 * @see #getPermissionReferenceURL()905 * @since 11975906 */907 public void setPermissionReferenceURL(String url) {908 permissionReferenceURL = url;909 }910 911 /**912 * Sets the privacy policy URL.913 * @param url The url.914 * @see #getPrivacyPolicyURL()915 * @since 16127916 */917 public void setPrivacyPolicyURL(String url) {918 privacyPolicyURL = url;919 }920 921 /**922 * Sets the text to display to the user as terms of use.923 * @param text The text924 * @see #getTermsOfUseText()925 */926 public void setTermsOfUseText(String text) {927 termsOfUseText = text;928 }929 930 /**931 * Sets a url that links to the terms of use text.932 * @param text The url.933 * @see #getTermsOfUseURL()934 */935 public void setTermsOfUseURL(String text) {936 termsOfUseURL = text;937 }938 939 /**940 632 * Sets the extended URL of this entry. 941 633 * @param url Entry extended URL containing in addition of service URL, its type and min/max zoom info … … 946 638 // Default imagery type is WMS 947 639 this.url = url; 948 this. imageryType = ImageryType.WMS;640 this.sourceType = ImageryType.WMS; 949 641 950 642 defaultMaxZoom = 0; … … 954 646 if (m.matches()) { 955 647 this.url = m.group(3); 956 this. imageryType = type;648 this.sourceType = type; 957 649 if (m.group(2) != null) { 958 650 defaultMaxZoom = Integer.parseInt(m.group(2)); … … 974 666 975 667 /** 976 * Returns the entry name.977 * @return The entry name978 * @since 6968979 */980 public String getOriginalName() {981 return this.origName != null ? this.origName : this.name;982 }983 984 /**985 * Sets the entry name and handle translation.986 * @param language The used language987 * @param name The entry name988 * @since 8091989 */990 public void setName(String language, String name) {991 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);992 if (LanguageInfo.isBetterLanguage(langName, language)) {993 this.name = isdefault ? tr(name) : name;994 this.langName = language;995 }996 if (origName == null || isdefault) {997 this.origName = name;998 }999 }1000 1001 /**1002 * Store the id of this info to the preferences and clear it afterwards.1003 */1004 public void clearId() {1005 if (this.id != null) {1006 Collection<String> newAddedIds = new TreeSet<>(Config.getPref().getList("imagery.layers.addedIds"));1007 newAddedIds.add(this.id);1008 Config.getPref().putList("imagery.layers.addedIds", new ArrayList<>(newAddedIds));1009 }1010 setId(null);1011 }1012 1013 /**1014 * Determines if this entry is enabled by default.1015 * @return {@code true} if this entry is enabled by default, {@code false} otherwise1016 */1017 public boolean isDefaultEntry() {1018 return defaultEntry;1019 }1020 1021 /**1022 * Sets the default state of this entry.1023 * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise1024 */1025 public void setDefaultEntry(boolean defaultEntry) {1026 this.defaultEntry = defaultEntry;1027 }1028 1029 /**1030 668 * Gets the pixel per degree value 1031 669 * @return The ppd value. … … 1053 691 } 1054 692 1055 /**1056 * Returns the description text when existing.1057 * @return The description1058 * @since 80651059 */1060 public String getDescription() {1061 return this.description;1062 }1063 1064 /**1065 * Sets the description text when existing.1066 * @param language The used language1067 * @param description the imagery description text1068 * @since 80911069 */1070 public void setDescription(String language, String description) {1071 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);1072 if (LanguageInfo.isBetterLanguage(langDescription, language)) {1073 this.description = isdefault ? tr(description) : description;1074 this.langDescription = intern(language);1075 }1076 }1077 1078 /**1079 * Return the sorted list of activated Imagery IDs.1080 * @return sorted list of activated Imagery IDs1081 * @since 135361082 */1083 public static Collection<String> getActiveIds() {1084 IPreferences pref = Config.getPref();1085 if (pref == null) {1086 return Collections.emptyList();1087 }1088 List<ImageryPreferenceEntry> entries = StructUtils.getListOfStructs(pref, "imagery.entries", null, ImageryPreferenceEntry.class);1089 if (entries == null) {1090 return Collections.emptyList();1091 }1092 return entries.stream()1093 .filter(prefEntry -> prefEntry.id != null && !prefEntry.id.isEmpty())1094 .map(prefEntry -> prefEntry.id)1095 .sorted()1096 .collect(Collectors.toList());1097 }1098 693 1099 694 /** … … 1102 697 * @since 8065 1103 698 */ 699 @Override 1104 700 public String getToolTipText() { 1105 701 StringBuilder res = new StringBuilder(getName()); … … 1134 730 1135 731 /** 1136 * Returns the EULA acceptance URL, if any.1137 * @return The URL to an EULA text that has to be accepted before use, or {@code null}1138 */1139 public String getEulaAcceptanceRequired() {1140 return eulaAcceptanceRequired;1141 }1142 1143 /**1144 * Sets the EULA acceptance URL.1145 * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use1146 */1147 public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {1148 this.eulaAcceptanceRequired = eulaAcceptanceRequired;1149 }1150 1151 /**1152 * Returns the ISO 3166-1-alpha-2 country code.1153 * @return The country code (2 letters)1154 */1155 public String getCountryCode() {1156 return countryCode;1157 }1158 1159 /**1160 * Sets the ISO 3166-1-alpha-2 country code.1161 * @param countryCode The country code (2 letters)1162 */1163 public void setCountryCode(String countryCode) {1164 this.countryCode = intern(countryCode);1165 }1166 1167 /**1168 * Returns the date information.1169 * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where1170 * DD and MM as well as a second date are optional)1171 * @since 115701172 */1173 public String getDate() {1174 return date;1175 }1176 1177 /**1178 * Sets the date information.1179 * @param date The date information1180 * @since 115701181 */1182 public void setDate(String date) {1183 this.date = date;1184 }1185 1186 /**1187 * Returns the entry icon.1188 * @return The entry icon1189 */1190 public String getIcon() {1191 return icon;1192 }1193 1194 /**1195 * Sets the entry icon.1196 * @param icon The entry icon1197 */1198 public void setIcon(String icon) {1199 this.icon = intern(icon);1200 }1201 1202 /**1203 732 * Get the projections supported by the server. Only relevant for 1204 733 * WMS-type ImageryInfo at the moment. … … 1226 755 */ 1227 756 public String getExtendedUrl() { 1228 return imageryType.getTypeString() + (defaultMaxZoom != 0757 return sourceType.getTypeString() + (defaultMaxZoom != 0 1229 758 ? ('['+(defaultMinZoom != 0 ? (Integer.toString(defaultMinZoom) + ',') : "")+defaultMaxZoom+']') : "") + ':' + url; 1230 759 } … … 1255 784 1256 785 /** 1257 * Determines if this entry requires attribution.1258 * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise1259 */1260 public boolean hasAttribution() {1261 return attributionText != null;1262 }1263 1264 /**1265 * Copies attribution from another {@code ImageryInfo}.1266 * @param i The other imagery info to get attribution from1267 */1268 public void copyAttribution(ImageryInfo i) {1269 this.attributionImage = i.attributionImage;1270 this.attributionImageURL = i.attributionImageURL;1271 this.attributionText = i.attributionText;1272 this.attributionLinkURL = i.attributionLinkURL;1273 this.termsOfUseText = i.termsOfUseText;1274 this.termsOfUseURL = i.termsOfUseURL;1275 }1276 1277 /**1278 * Applies the attribution from this object to a tile source.1279 * @param s The tile source1280 */1281 public void setAttribution(AbstractTileSource s) {1282 if (attributionText != null) {1283 if ("osm".equals(attributionText)) {1284 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));1285 } else {1286 s.setAttributionText(attributionText);1287 }1288 }1289 if (attributionLinkURL != null) {1290 if ("osm".equals(attributionLinkURL)) {1291 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());1292 } else {1293 s.setAttributionLinkURL(attributionLinkURL);1294 }1295 }1296 if (attributionImage != null) {1297 ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);1298 if (i != null) {1299 s.setAttributionImage(i.getImage());1300 }1301 }1302 if (attributionImageURL != null) {1303 s.setAttributionImageURL(attributionImageURL);1304 }1305 if (termsOfUseText != null) {1306 s.setTermsOfUseText(termsOfUseText);1307 }1308 if (termsOfUseURL != null) {1309 if ("osm".equals(termsOfUseURL)) {1310 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());1311 } else {1312 s.setTermsOfUseURL(termsOfUseURL);1313 }1314 }1315 }1316 1317 /**1318 786 * Returns the imagery type. 1319 787 * @return The imagery type 788 * @see SourceInfo#getSourceType 1320 789 */ 1321 790 public ImageryType getImageryType() { 1322 return imageryType;791 return super.getSourceType(); 1323 792 } 1324 793 … … 1326 795 * Sets the imagery type. 1327 796 * @param imageryType The imagery type 797 * @see SourceInfo#setSourceType 1328 798 */ 1329 799 public void setImageryType(ImageryType imageryType) { 1330 this.imageryType = imageryType;800 super.setSourceType(imageryType); 1331 801 } 1332 802 … … 1334 804 * Returns the imagery category. 1335 805 * @return The imagery category 806 * @see SourceInfo#getSourceCategory 1336 807 * @since 13792 1337 808 */ 1338 809 public ImageryCategory getImageryCategory() { 1339 return category;810 return super.getSourceCategory(); 1340 811 } 1341 812 … … 1343 814 * Sets the imagery category. 1344 815 * @param category The imagery category 816 * @see SourceInfo#setSourceCategory 1345 817 * @since 13792 1346 818 */ 1347 819 public void setImageryCategory(ImageryCategory category) { 1348 this.category = category;820 super.setSourceCategory(category); 1349 821 } 1350 822 … … 1352 824 * Returns the imagery category original string (don't use except for error checks). 1353 825 * @return The imagery category original string 826 * @see SourceInfo#getSourceCategoryOriginalString 1354 827 * @since 13792 1355 828 */ 1356 829 public String getImageryCategoryOriginalString() { 1357 return categoryOriginalString;830 return super.getSourceCategoryOriginalString(); 1358 831 } 1359 832 … … 1361 834 * Sets the imagery category original string (don't use except for error checks). 1362 835 * @param categoryOriginalString The imagery category original string 836 * @see SourceInfo#setSourceCategoryOriginalString 1363 837 * @since 13792 1364 838 */ 1365 839 public void setImageryCategoryOriginalString(String categoryOriginalString) { 1366 this.categoryOriginalString = intern(categoryOriginalString); 1367 } 1368 1369 /** 1370 * Returns true if this layer's URL is matched by one of the regular 1371 * expressions kept by the current OsmApi instance. 1372 * @return {@code true} is this entry is blacklisted, {@code false} otherwise 1373 */ 1374 public boolean isBlacklisted() { 1375 Capabilities capabilities = OsmApi.getOsmApi().getCapabilities(); 1376 return capabilities != null && capabilities.isOnImageryBlacklist(this.url); 1377 } 1378 1379 /** 1380 * Sets the map of <header name, header value> that if any of this header 1381 * will be returned, then this tile will be treated as "no tile at this zoom level" 1382 * 1383 * @param noTileHeaders Map of <header name, header value> which will be treated as "no tile at this zoom level" 1384 * @since 9613 1385 */ 1386 public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) { 1387 if (noTileHeaders == null || noTileHeaders.isEmpty()) { 1388 this.noTileHeaders = null; 1389 } else { 1390 this.noTileHeaders = noTileHeaders.toMap(); 1391 } 1392 } 1393 1394 @Override 1395 public Map<String, Set<String>> getNoTileHeaders() { 1396 return noTileHeaders; 1397 } 1398 1399 /** 1400 * Sets the map of <checksum type, checksum value> that if any tile with that checksum 1401 * will be returned, then this tile will be treated as "no tile at this zoom level" 1402 * 1403 * @param noTileChecksums Map of <checksum type, checksum value> which will be treated as "no tile at this zoom level" 1404 * @since 9613 1405 */ 1406 public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) { 1407 if (noTileChecksums == null || noTileChecksums.isEmpty()) { 1408 this.noTileChecksums = null; 1409 } else { 1410 this.noTileChecksums = noTileChecksums.toMap(); 1411 } 1412 } 1413 1414 @Override 1415 public Map<String, Set<String>> getNoTileChecksums() { 1416 return noTileChecksums; 1417 } 1418 1419 /** 1420 * Returns the map of <header name, metadata key> indicating, which HTTP headers should 1421 * be moved to metadata 1422 * 1423 * @param metadataHeaders map of <header name, metadata key> indicating, which HTTP headers should be moved to metadata 1424 * @since 8418 1425 */ 1426 public void setMetadataHeaders(Map<String, String> metadataHeaders) { 1427 if (metadataHeaders == null || metadataHeaders.isEmpty()) { 1428 this.metadataHeaders = null; 1429 } else { 1430 this.metadataHeaders = metadataHeaders; 1431 } 840 super.setSourceCategoryOriginalString(categoryOriginalString); 1432 841 } 1433 842 … … 1482 891 public void setOverlay(boolean overlay) { 1483 892 this.overlay = overlay; 1484 }1485 1486 /**1487 * Adds an old Id.1488 *1489 * @param id the Id to be added1490 * @since 135361491 */1492 public void addOldId(String id) {1493 if (oldIds == null) {1494 oldIds = new ArrayList<>();1495 }1496 oldIds.add(id);1497 }1498 1499 /**1500 * Get old Ids.1501 *1502 * @return collection of ids1503 * @since 135361504 */1505 public Collection<String> getOldIds() {1506 return oldIds;1507 }1508 1509 /**1510 * Adds a mirror entry. Mirror entries are completed with the data from the master entry1511 * and only describe another method to access identical data.1512 *1513 * @param entry the mirror to be added1514 * @since 96581515 */1516 public void addMirror(ImageryInfo entry) {1517 if (mirrors == null) {1518 mirrors = new ArrayList<>();1519 }1520 mirrors.add(entry);1521 }1522 1523 /**1524 * Returns the mirror entries. Entries are completed with master entry data.1525 *1526 * @return the list of mirrors1527 * @since 96581528 */1529 public List<ImageryInfo> getMirrors() {1530 List<ImageryInfo> l = new ArrayList<>();1531 if (mirrors != null) {1532 int num = 1;1533 for (ImageryInfo i : mirrors) {1534 ImageryInfo n = new ImageryInfo(this);1535 if (i.defaultMaxZoom != 0) {1536 n.defaultMaxZoom = i.defaultMaxZoom;1537 }1538 if (i.defaultMinZoom != 0) {1539 n.defaultMinZoom = i.defaultMinZoom;1540 }1541 n.setServerProjections(i.getServerProjections());1542 n.url = i.url;1543 n.imageryType = i.imageryType;1544 if (i.getTileSize() != 0) {1545 n.setTileSize(i.getTileSize());1546 }1547 if (i.getPrivacyPolicyURL() != null) {1548 n.setPrivacyPolicyURL(i.getPrivacyPolicyURL());1549 }1550 if (n.id != null) {1551 n.id = n.id + "_mirror"+num;1552 }1553 if (num > 1) {1554 n.name = tr("{0} mirror server {1}", n.name, num);1555 if (n.origName != null) {1556 n.origName += " mirror server " + num;1557 }1558 } else {1559 n.name = tr("{0} mirror server", n.name);1560 if (n.origName != null) {1561 n.origName += " mirror server";1562 }1563 }1564 l.add(n);1565 ++num;1566 }1567 }1568 return l;1569 }1570 1571 /**1572 * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)1573 * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer1574 * to work on1575 * @return Collection of the layer names1576 */1577 public List<DefaultLayer> getDefaultLayers() {1578 return defaultLayers;1579 }1580 1581 /**1582 * Sets the default layers that user will work with1583 * @param layers set the list of default layers1584 */1585 public void setDefaultLayers(List<DefaultLayer> layers) {1586 this.defaultLayers = Utils.toUnmodifiableList(layers);1587 }1588 1589 /**1590 * Returns custom HTTP headers that should be sent with request towards imagery provider1591 * @return headers1592 */1593 public Map<String, String> getCustomHttpHeaders() {1594 return customHttpHeaders;1595 }1596 1597 /**1598 * Sets custom HTTP headers that should be sent with request towards imagery provider1599 * @param customHttpHeaders http headers1600 */1601 public void setCustomHttpHeaders(Map<String, String> customHttpHeaders) {1602 this.customHttpHeaders = Utils.toUnmodifiableMap(customHttpHeaders);1603 893 } 1604 894 … … 1655 945 } 1656 946 1657 private static String intern(String string) { 1658 return string == null ? null : string.intern(); 947 /** 948 * Return the sorted list of activated source IDs. 949 * @return sorted list of activated source IDs 950 * @since 13536 951 */ 952 public static Collection<String> getActiveIds() { 953 return getActiveIds(ImageryInfo.class); 1659 954 } 1660 955 } -
trunk/src/org/openstreetmap/josm/tools/Utils.java
r16436 r16545 1911 1911 return rawString.trim(); 1912 1912 } 1913 1914 /** 1915 * Intern a string 1916 * @param string The string to intern 1917 * @return The interned string 1918 * @since 16545 1919 */ 1920 public static String intern(String string) { 1921 return string == null ? null : string.intern(); 1922 } 1913 1923 }
Note:
See TracChangeset
for help on using the changeset viewer.