source: josm/trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java@ 14214

Last change on this file since 14214 was 14214, checked in by Don-vip, 6 years ago

sonarqube - squid:S4551 - Enum values should be compared with "=="

  • Property svn:eol-style set to native
File size: 53.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Image;
7import java.io.StringReader;
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collection;
11import java.util.Collections;
12import java.util.List;
13import java.util.Locale;
14import java.util.Map;
15import java.util.Objects;
16import java.util.Optional;
17import java.util.Set;
18import java.util.TreeSet;
19import java.util.concurrent.ConcurrentHashMap;
20import java.util.concurrent.TimeUnit;
21import java.util.regex.Matcher;
22import java.util.regex.Pattern;
23import java.util.stream.Collectors;
24
25import javax.json.Json;
26import javax.json.JsonObject;
27import javax.json.JsonReader;
28import javax.json.stream.JsonCollectors;
29import javax.swing.ImageIcon;
30
31import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
32import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
33import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
34import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
35import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
36import org.openstreetmap.josm.data.Bounds;
37import org.openstreetmap.josm.data.StructUtils;
38import org.openstreetmap.josm.data.StructUtils.StructEntry;
39import org.openstreetmap.josm.io.Capabilities;
40import org.openstreetmap.josm.io.OsmApi;
41import org.openstreetmap.josm.spi.preferences.Config;
42import org.openstreetmap.josm.spi.preferences.IPreferences;
43import org.openstreetmap.josm.tools.CheckParameterUtil;
44import org.openstreetmap.josm.tools.ImageProvider;
45import org.openstreetmap.josm.tools.LanguageInfo;
46import org.openstreetmap.josm.tools.Logging;
47import org.openstreetmap.josm.tools.MultiMap;
48import org.openstreetmap.josm.tools.Utils;
49
50/**
51 * Class that stores info about an image background layer.
52 *
53 * @author Frederik Ramm
54 */
55public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInfo>, Attributed {
56
57 /**
58 * Type of imagery entry.
59 */
60 public enum ImageryType {
61 /** A WMS (Web Map Service) entry. **/
62 WMS("wms"),
63 /** A TMS (Tile Map Service) entry. **/
64 TMS("tms"),
65 /** TMS entry for Microsoft Bing. */
66 BING("bing"),
67 /** TMS entry for Russian company <a href="https://wiki.openstreetmap.org/wiki/WikiProject_Russia/kosmosnimki">ScanEx</a>. **/
68 SCANEX("scanex"),
69 /** A WMS endpoint entry only stores the WMS server info, without layer, which are chosen later by the user. **/
70 WMS_ENDPOINT("wms_endpoint"),
71 /** WMTS stores GetCapabilities URL. Does not store any information about the layer **/
72 WMTS("wmts");
73
74
75 private final String typeString;
76
77 ImageryType(String typeString) {
78 this.typeString = typeString;
79 }
80
81 /**
82 * Returns the unique string identifying this type.
83 * @return the unique string identifying this type
84 * @since 6690
85 */
86 public final String getTypeString() {
87 return typeString;
88 }
89
90 /**
91 * Returns the imagery type from the given type string.
92 * @param s The type string
93 * @return the imagery type matching the given type string
94 */
95 public static ImageryType fromString(String s) {
96 for (ImageryType type : ImageryType.values()) {
97 if (type.getTypeString().equals(s)) {
98 return type;
99 }
100 }
101 return null;
102 }
103 }
104
105 /**
106 * Category of imagery entry.
107 * @since 13792
108 */
109 public enum ImageryCategory {
110 /** A aerial or satellite photo. **/
111 PHOTO("photo", tr("Aerial or satellite photo")),
112 /** A map. **/
113 MAP("map", tr("Map")),
114 /** A historic or otherwise outdated map. */
115 HISTORICMAP("historicmap", tr("Historic or otherwise outdated map")),
116 /** A map based on OSM data. **/
117 OSMBASEDMAP("osmbasedmap", tr("Map based on OSM data")),
118 /** A historic or otherwise outdated aerial or satellite photo. **/
119 HISTORICPHOTO("historicphoto", tr("Historic or otherwise outdated aerial or satellite photo")),
120 /** Any other type of imagery **/
121 OTHER("other", tr("Imagery not matching any other category"));
122
123 private final String category;
124 private final String description;
125
126 ImageryCategory(String category, String description) {
127 this.category = category;
128 this.description = description;
129 }
130
131 /**
132 * Returns the unique string identifying this category.
133 * @return the unique string identifying this category
134 */
135 public final String getCategoryString() {
136 return category;
137 }
138
139 /**
140 * Returns the description of this category.
141 * @return the description of this category
142 */
143 public final String getDescription() {
144 return description;
145 }
146
147 /**
148 * Returns the imagery category from the given category string.
149 * @param s The category string
150 * @return the imagery category matching the given category string
151 */
152 public static ImageryCategory fromString(String s) {
153 for (ImageryCategory category : ImageryCategory.values()) {
154 if (category.getCategoryString().equals(s)) {
155 return category;
156 }
157 }
158 return null;
159 }
160 }
161
162 /**
163 * Multi-polygon bounds for imagery backgrounds.
164 * Used to display imagery coverage in preferences and to determine relevant imagery entries based on edit location.
165 */
166 public static class ImageryBounds extends Bounds {
167
168 /**
169 * Constructs a new {@code ImageryBounds} from string.
170 * @param asString The string containing the list of shapes defining this bounds
171 * @param separator The shape separator in the given string, usually a comma
172 */
173 public ImageryBounds(String asString, String separator) {
174 super(asString, separator);
175 }
176
177 private List<Shape> shapes = new ArrayList<>();
178
179 /**
180 * Adds a new shape to this bounds.
181 * @param shape The shape to add
182 */
183 public final void addShape(Shape shape) {
184 this.shapes.add(shape);
185 }
186
187 /**
188 * Sets the list of shapes defining this bounds.
189 * @param shapes The list of shapes defining this bounds.
190 */
191 public final void setShapes(List<Shape> shapes) {
192 this.shapes = shapes;
193 }
194
195 /**
196 * Returns the list of shapes defining this bounds.
197 * @return The list of shapes defining this bounds
198 */
199 public final List<Shape> getShapes() {
200 return shapes;
201 }
202
203 @Override
204 public int hashCode() {
205 return Objects.hash(super.hashCode(), shapes);
206 }
207
208 @Override
209 public boolean equals(Object o) {
210 if (this == o) return true;
211 if (o == null || getClass() != o.getClass()) return false;
212 if (!super.equals(o)) return false;
213 ImageryBounds that = (ImageryBounds) o;
214 return Objects.equals(shapes, that.shapes);
215 }
216 }
217
218 /** original name of the imagery entry in case of translation call, for multiple languages English when possible */
219 private String origName;
220 /** (original) language of the translated name entry */
221 private String langName;
222 /** whether this is a entry activated by default or not */
223 private boolean defaultEntry;
224 /** Whether this service requires a explicit EULA acceptance before it can be activated */
225 private String eulaAcceptanceRequired;
226 /** type of the imagery servics - WMS, TMS, ... */
227 private ImageryType imageryType = ImageryType.WMS;
228 private double pixelPerDegree;
229 /** maximum zoom level for TMS imagery */
230 private int defaultMaxZoom;
231 /** minimum zoom level for TMS imagery */
232 private int defaultMinZoom;
233 /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */
234 private ImageryBounds bounds;
235 /** projections supported by WMS servers */
236 private List<String> serverProjections = Collections.emptyList();
237 /** description of the imagery entry, should contain notes what type of data it is */
238 private String description;
239 /** language of the description entry */
240 private String langDescription;
241 /** Text of a text attribution displayed when using the imagery */
242 private String attributionText;
243 /** Link to a reference stating the permission for OSM usage */
244 private String permissionReferenceURL;
245 /** Link behind the text attribution displayed when using the imagery */
246 private String attributionLinkURL;
247 /** Image of a graphical attribution displayed when using the imagery */
248 private String attributionImage;
249 /** Link behind the graphical attribution displayed when using the imagery */
250 private String attributionImageURL;
251 /** Text with usage terms displayed when using the imagery */
252 private String termsOfUseText;
253 /** Link behind the text with usage terms displayed when using the imagery */
254 private String termsOfUseURL;
255 /** country code of the imagery (for country specific imagery) */
256 private String countryCode = "";
257 /**
258 * creation date of the imagery (in the form YYYY-MM-DD;YYYY-MM-DD, where
259 * DD and MM as well as a second date are optional)
260 * @since 11570
261 */
262 private String date;
263 /**
264 * marked as best in other editors
265 * @since 11575
266 */
267 private boolean bestMarked;
268 /**
269 * marked as overlay
270 * @since 13536
271 */
272 private boolean overlay;
273 /**
274 * list of old IDs, only for loading, not handled anywhere else
275 * @since 13536
276 */
277 private Collection<String> oldIds;
278 /** mirrors of different type for this entry */
279 private List<ImageryInfo> mirrors;
280 /** icon used in menu */
281 private String icon;
282 /** is the geo reference correct - don't offer offset handling */
283 private boolean isGeoreferenceValid;
284 /** which layers should be activated by default on layer addition. **/
285 private List<DefaultLayer> defaultLayers = new ArrayList<>();
286 /** HTTP headers **/
287 private Map<String, String> customHttpHeaders = new ConcurrentHashMap<>();
288 /** Should this map be transparent **/
289 private boolean transparent = true;
290 private int minimumTileExpire = (int) TimeUnit.MILLISECONDS.toSeconds(TMSCachedTileLoaderJob.MINIMUM_EXPIRES.get());
291 /** category of the imagery */
292 private ImageryCategory category;
293 /** category of the imagery (input string, not saved, copied or used otherwise except for error checks) */
294 private String categoryOriginalString;
295 /** when adding a field, also adapt the:
296 * {@link #ImageryPreferenceEntry ImageryPreferenceEntry object}
297 * {@link #ImageryPreferenceEntry#ImageryPreferenceEntry(ImageryInfo) ImageryPreferenceEntry constructor}
298 * {@link #ImageryInfo(ImageryPreferenceEntry) ImageryInfo constructor}
299 * {@link #ImageryInfo(ImageryInfo) ImageryInfo constructor}
300 * {@link #equalsPref(ImageryPreferenceEntry) equalsPref method}
301 **/
302
303 /**
304 * Auxiliary class to save an {@link ImageryInfo} object in the preferences.
305 */
306 public static class ImageryPreferenceEntry {
307 @StructEntry String name;
308 @StructEntry String d;
309 @StructEntry String id;
310 @StructEntry String type;
311 @StructEntry String url;
312 @StructEntry double pixel_per_eastnorth;
313 @StructEntry String eula;
314 @StructEntry String attribution_text;
315 @StructEntry String attribution_url;
316 @StructEntry String permission_reference_url;
317 @StructEntry String logo_image;
318 @StructEntry String logo_url;
319 @StructEntry String terms_of_use_text;
320 @StructEntry String terms_of_use_url;
321 @StructEntry String country_code = "";
322 @StructEntry String date;
323 @StructEntry int max_zoom;
324 @StructEntry int min_zoom;
325 @StructEntry String cookies;
326 @StructEntry String bounds;
327 @StructEntry String shapes;
328 @StructEntry String projections;
329 @StructEntry String icon;
330 @StructEntry String description;
331 @StructEntry MultiMap<String, String> noTileHeaders;
332 @StructEntry MultiMap<String, String> noTileChecksums;
333 @StructEntry int tileSize = -1;
334 @StructEntry Map<String, String> metadataHeaders;
335 @StructEntry boolean valid_georeference;
336 @StructEntry boolean bestMarked;
337 @StructEntry boolean modTileFeatures;
338 @StructEntry boolean overlay;
339 @StructEntry String default_layers;
340 @StructEntry Map<String, String> customHttpHeaders;
341 @StructEntry boolean transparent;
342 @StructEntry int minimumTileExpire;
343 @StructEntry String category;
344
345 /**
346 * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
347 */
348 public ImageryPreferenceEntry() {
349 // Do nothing
350 }
351
352 /**
353 * Constructs a new {@code ImageryPreferenceEntry} from a given {@code ImageryInfo}.
354 * @param i The corresponding imagery info
355 */
356 public ImageryPreferenceEntry(ImageryInfo i) {
357 name = i.name;
358 id = i.id;
359 type = i.imageryType.getTypeString();
360 url = i.url;
361 pixel_per_eastnorth = i.pixelPerDegree;
362 eula = i.eulaAcceptanceRequired;
363 attribution_text = i.attributionText;
364 attribution_url = i.attributionLinkURL;
365 permission_reference_url = i.permissionReferenceURL;
366 date = i.date;
367 bestMarked = i.bestMarked;
368 overlay = i.overlay;
369 logo_image = i.attributionImage;
370 logo_url = i.attributionImageURL;
371 terms_of_use_text = i.termsOfUseText;
372 terms_of_use_url = i.termsOfUseURL;
373 country_code = i.countryCode;
374 max_zoom = i.defaultMaxZoom;
375 min_zoom = i.defaultMinZoom;
376 cookies = i.cookies;
377 icon = i.icon;
378 description = i.description;
379 category = i.category != null ? i.category.getCategoryString() : null;
380 if (i.bounds != null) {
381 bounds = i.bounds.encodeAsString(",");
382 StringBuilder shapesString = new StringBuilder();
383 for (Shape s : i.bounds.getShapes()) {
384 if (shapesString.length() > 0) {
385 shapesString.append(';');
386 }
387 shapesString.append(s.encodeAsString(","));
388 }
389 if (shapesString.length() > 0) {
390 shapes = shapesString.toString();
391 }
392 }
393 if (!i.serverProjections.isEmpty()) {
394 projections = i.serverProjections.stream().collect(Collectors.joining(","));
395 }
396 if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
397 noTileHeaders = new MultiMap<>(i.noTileHeaders);
398 }
399
400 if (i.noTileChecksums != null && !i.noTileChecksums.isEmpty()) {
401 noTileChecksums = new MultiMap<>(i.noTileChecksums);
402 }
403
404 if (i.metadataHeaders != null && !i.metadataHeaders.isEmpty()) {
405 metadataHeaders = i.metadataHeaders;
406 }
407
408 tileSize = i.getTileSize();
409
410 valid_georeference = i.isGeoreferenceValid();
411 modTileFeatures = i.isModTileFeatures();
412 if (!i.defaultLayers.isEmpty()) {
413 default_layers = i.defaultLayers.stream().map(DefaultLayer::toJson).collect(JsonCollectors.toJsonArray()).toString();
414 }
415 customHttpHeaders = i.customHttpHeaders;
416 transparent = i.isTransparent();
417 minimumTileExpire = i.minimumTileExpire;
418 }
419
420 @Override
421 public String toString() {
422 StringBuilder s = new StringBuilder("ImageryPreferenceEntry [name=").append(name);
423 if (id != null) {
424 s.append(" id=").append(id);
425 }
426 s.append(']');
427 return s.toString();
428 }
429 }
430
431 /**
432 * Constructs a new WMS {@code ImageryInfo}.
433 */
434 public ImageryInfo() {
435 super();
436 }
437
438 /**
439 * Constructs a new WMS {@code ImageryInfo} with a given name.
440 * @param name The entry name
441 */
442 public ImageryInfo(String name) {
443 super(name);
444 }
445
446 /**
447 * Constructs a new WMS {@code ImageryInfo} with given name and extended URL.
448 * @param name The entry name
449 * @param url The entry extended URL
450 */
451 public ImageryInfo(String name, String url) {
452 this(name);
453 setExtendedUrl(url);
454 }
455
456 /**
457 * Constructs a new WMS {@code ImageryInfo} with given name, extended and EULA URLs.
458 * @param name The entry name
459 * @param url The entry URL
460 * @param eulaAcceptanceRequired The EULA URL
461 */
462 public ImageryInfo(String name, String url, String eulaAcceptanceRequired) {
463 this(name);
464 setExtendedUrl(url);
465 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
466 }
467
468 /**
469 * Constructs a new {@code ImageryInfo} with given name, url, extended and EULA URLs.
470 * @param name The entry name
471 * @param url The entry URL
472 * @param type The entry imagery type. If null, WMS will be used as default
473 * @param eulaAcceptanceRequired The EULA URL
474 * @param cookies The data part of HTTP cookies header in case the service requires cookies to work
475 * @throws IllegalArgumentException if type refers to an unknown imagery type
476 */
477 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies) {
478 this(name);
479 setExtendedUrl(url);
480 ImageryType t = ImageryType.fromString(type);
481 this.cookies = cookies;
482 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
483 if (t != null) {
484 this.imageryType = t;
485 } else if (type != null && !type.isEmpty()) {
486 throw new IllegalArgumentException("unknown type: "+type);
487 }
488 }
489
490 /**
491 * Constructs a new {@code ImageryInfo} with given name, url, id, extended and EULA URLs.
492 * @param name The entry name
493 * @param url The entry URL
494 * @param type The entry imagery type. If null, WMS will be used as default
495 * @param eulaAcceptanceRequired The EULA URL
496 * @param cookies The data part of HTTP cookies header in case the service requires cookies to work
497 * @param id tile id
498 * @throws IllegalArgumentException if type refers to an unknown imagery type
499 */
500 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies, String id) {
501 this(name, url, type, eulaAcceptanceRequired, cookies);
502 setId(id);
503 }
504
505 /**
506 * Constructs a new {@code ImageryInfo} from an imagery preference entry.
507 * @param e The imagery preference entry
508 */
509 public ImageryInfo(ImageryPreferenceEntry e) {
510 super(e.name, e.url, e.id);
511 CheckParameterUtil.ensureParameterNotNull(e.name, "name");
512 CheckParameterUtil.ensureParameterNotNull(e.url, "url");
513 description = e.description;
514 cookies = e.cookies;
515 eulaAcceptanceRequired = e.eula;
516 imageryType = ImageryType.fromString(e.type);
517 if (imageryType == null) throw new IllegalArgumentException("unknown type");
518 pixelPerDegree = e.pixel_per_eastnorth;
519 defaultMaxZoom = e.max_zoom;
520 defaultMinZoom = e.min_zoom;
521 if (e.bounds != null) {
522 bounds = new ImageryBounds(e.bounds, ",");
523 if (e.shapes != null) {
524 try {
525 for (String s : e.shapes.split(";")) {
526 bounds.addShape(new Shape(s, ","));
527 }
528 } catch (IllegalArgumentException ex) {
529 Logging.warn(ex);
530 }
531 }
532 }
533 if (e.projections != null && !e.projections.isEmpty()) {
534 // split generates null element on empty string which gives one element Array[null]
535 serverProjections = Arrays.asList(e.projections.split(","));
536 }
537 attributionText = e.attribution_text;
538 attributionLinkURL = e.attribution_url;
539 permissionReferenceURL = e.permission_reference_url;
540 attributionImage = e.logo_image;
541 attributionImageURL = e.logo_url;
542 date = e.date;
543 bestMarked = e.bestMarked;
544 overlay = e.overlay;
545 termsOfUseText = e.terms_of_use_text;
546 termsOfUseURL = e.terms_of_use_url;
547 countryCode = e.country_code;
548 icon = e.icon;
549 if (e.noTileHeaders != null) {
550 noTileHeaders = e.noTileHeaders.toMap();
551 }
552 if (e.noTileChecksums != null) {
553 noTileChecksums = e.noTileChecksums.toMap();
554 }
555 setTileSize(e.tileSize);
556 metadataHeaders = e.metadataHeaders;
557 isGeoreferenceValid = e.valid_georeference;
558 modTileFeatures = e.modTileFeatures;
559 if (e.default_layers != null) {
560 try (JsonReader jsonReader = Json.createReader(new StringReader(e.default_layers))) {
561 defaultLayers = jsonReader.
562 readArray().
563 stream().
564 map(x -> DefaultLayer.fromJson((JsonObject) x, imageryType)).
565 collect(Collectors.toList());
566 }
567 }
568 customHttpHeaders = e.customHttpHeaders;
569 transparent = e.transparent;
570 minimumTileExpire = e.minimumTileExpire;
571 category = ImageryCategory.fromString(e.category);
572 }
573
574 /**
575 * Constructs a new {@code ImageryInfo} from an existing one.
576 * @param i The other imagery info
577 */
578 public ImageryInfo(ImageryInfo i) {
579 super(i.name, i.url, i.id);
580 this.noTileHeaders = i.noTileHeaders;
581 this.noTileChecksums = i.noTileChecksums;
582 this.minZoom = i.minZoom;
583 this.maxZoom = i.maxZoom;
584 this.cookies = i.cookies;
585 this.tileSize = i.tileSize;
586 this.metadataHeaders = i.metadataHeaders;
587 this.modTileFeatures = i.modTileFeatures;
588
589 this.origName = i.origName;
590 this.langName = i.langName;
591 this.defaultEntry = i.defaultEntry;
592 this.eulaAcceptanceRequired = null;
593 this.imageryType = i.imageryType;
594 this.pixelPerDegree = i.pixelPerDegree;
595 this.defaultMaxZoom = i.defaultMaxZoom;
596 this.defaultMinZoom = i.defaultMinZoom;
597 this.bounds = i.bounds;
598 this.serverProjections = i.serverProjections;
599 this.description = i.description;
600 this.langDescription = i.langDescription;
601 this.attributionText = i.attributionText;
602 this.permissionReferenceURL = i.permissionReferenceURL;
603 this.attributionLinkURL = i.attributionLinkURL;
604 this.attributionImage = i.attributionImage;
605 this.attributionImageURL = i.attributionImageURL;
606 this.termsOfUseText = i.termsOfUseText;
607 this.termsOfUseURL = i.termsOfUseURL;
608 this.countryCode = i.countryCode;
609 this.date = i.date;
610 this.bestMarked = i.bestMarked;
611 this.overlay = i.overlay;
612 // do not copy field {@code mirrors}
613 this.icon = i.icon;
614 this.isGeoreferenceValid = i.isGeoreferenceValid;
615 this.defaultLayers = i.defaultLayers;
616 this.customHttpHeaders = i.customHttpHeaders;
617 this.transparent = i.transparent;
618 this.minimumTileExpire = i.minimumTileExpire;
619 this.category = i.category;
620 }
621
622 @Override
623 public int hashCode() {
624 return Objects.hash(url, imageryType);
625 }
626
627 /**
628 * Check if this object equals another ImageryInfo with respect to the properties
629 * that get written to the preference file.
630 *
631 * The field {@link #pixelPerDegree} is ignored.
632 *
633 * @param other the ImageryInfo object to compare to
634 * @return true if they are equal
635 */
636 public boolean equalsPref(ImageryInfo other) {
637 if (other == null) {
638 return false;
639 }
640
641 // CHECKSTYLE.OFF: BooleanExpressionComplexity
642 return
643 Objects.equals(this.name, other.name) &&
644 Objects.equals(this.id, other.id) &&
645 Objects.equals(this.url, other.url) &&
646 Objects.equals(this.modTileFeatures, other.modTileFeatures) &&
647 Objects.equals(this.bestMarked, other.bestMarked) &&
648 Objects.equals(this.overlay, other.overlay) &&
649 Objects.equals(this.isGeoreferenceValid, other.isGeoreferenceValid) &&
650 Objects.equals(this.cookies, other.cookies) &&
651 Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
652 Objects.equals(this.imageryType, other.imageryType) &&
653 Objects.equals(this.defaultMaxZoom, other.defaultMaxZoom) &&
654 Objects.equals(this.defaultMinZoom, other.defaultMinZoom) &&
655 Objects.equals(this.bounds, other.bounds) &&
656 Objects.equals(this.serverProjections, other.serverProjections) &&
657 Objects.equals(this.attributionText, other.attributionText) &&
658 Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
659 Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) &&
660 Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
661 Objects.equals(this.attributionImage, other.attributionImage) &&
662 Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
663 Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
664 Objects.equals(this.countryCode, other.countryCode) &&
665 Objects.equals(this.date, other.date) &&
666 Objects.equals(this.icon, other.icon) &&
667 Objects.equals(this.description, other.description) &&
668 Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
669 Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
670 Objects.equals(this.metadataHeaders, other.metadataHeaders) &&
671 Objects.equals(this.defaultLayers, other.defaultLayers) &&
672 Objects.equals(this.customHttpHeaders, other.customHttpHeaders) &&
673 Objects.equals(this.transparent, other.transparent) &&
674 Objects.equals(this.minimumTileExpire, other.minimumTileExpire) &&
675 Objects.equals(this.category, other.category);
676 // CHECKSTYLE.ON: BooleanExpressionComplexity
677 }
678
679 @Override
680 public boolean equals(Object o) {
681 if (this == o) return true;
682 if (o == null || getClass() != o.getClass()) return false;
683 ImageryInfo that = (ImageryInfo) o;
684 return imageryType == that.imageryType && Objects.equals(url, that.url);
685 }
686
687 @Override
688 public String toString() {
689 return "ImageryInfo{" +
690 "name='" + name + '\'' +
691 ", countryCode='" + countryCode + '\'' +
692 ", url='" + url + '\'' +
693 ", imageryType=" + imageryType +
694 '}';
695 }
696
697 @Override
698 public int compareTo(ImageryInfo in) {
699 int i = countryCode.compareTo(in.countryCode);
700 if (i == 0) {
701 i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
702 }
703 if (i == 0) {
704 i = url.compareTo(in.url);
705 }
706 if (i == 0) {
707 i = Double.compare(pixelPerDegree, in.pixelPerDegree);
708 }
709 return i;
710 }
711
712 /**
713 * Determines if URL is equal to given imagery info.
714 * @param in imagery info
715 * @return {@code true} if URL is equal to given imagery info
716 */
717 public boolean equalsBaseValues(ImageryInfo in) {
718 return url.equals(in.url);
719 }
720
721 /**
722 * Sets the pixel per degree value.
723 * @param ppd The ppd value
724 * @see #getPixelPerDegree()
725 */
726 public void setPixelPerDegree(double ppd) {
727 this.pixelPerDegree = ppd;
728 }
729
730 /**
731 * Sets the maximum zoom level.
732 * @param defaultMaxZoom The maximum zoom level
733 */
734 public void setDefaultMaxZoom(int defaultMaxZoom) {
735 this.defaultMaxZoom = defaultMaxZoom;
736 }
737
738 /**
739 * Sets the minimum zoom level.
740 * @param defaultMinZoom The minimum zoom level
741 */
742 public void setDefaultMinZoom(int defaultMinZoom) {
743 this.defaultMinZoom = defaultMinZoom;
744 }
745
746 /**
747 * Sets the imagery polygonial bounds.
748 * @param b The imagery bounds (non-rectangular)
749 */
750 public void setBounds(ImageryBounds b) {
751 this.bounds = b;
752 }
753
754 /**
755 * Returns the imagery polygonial bounds.
756 * @return The imagery bounds (non-rectangular)
757 */
758 public ImageryBounds getBounds() {
759 return bounds;
760 }
761
762 @Override
763 public boolean requiresAttribution() {
764 return attributionText != null || attributionLinkURL != null || attributionImage != null
765 || termsOfUseText != null || termsOfUseURL != null;
766 }
767
768 @Override
769 public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
770 return attributionText;
771 }
772
773 @Override
774 public String getAttributionLinkURL() {
775 return attributionLinkURL;
776 }
777
778 /**
779 * Return the permission reference URL.
780 * @return The url
781 * @see #setPermissionReferenceURL
782 * @since 11975
783 */
784 public String getPermissionReferenceURL() {
785 return permissionReferenceURL;
786 }
787
788 @Override
789 public Image getAttributionImage() {
790 ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
791 if (i != null) {
792 return i.getImage();
793 }
794 return null;
795 }
796
797 /**
798 * Return the raw attribution logo information (an URL to the image).
799 * @return The url text
800 * @since 12257
801 */
802 public String getAttributionImageRaw() {
803 return attributionImage;
804 }
805
806 @Override
807 public String getAttributionImageURL() {
808 return attributionImageURL;
809 }
810
811 @Override
812 public String getTermsOfUseText() {
813 return termsOfUseText;
814 }
815
816 @Override
817 public String getTermsOfUseURL() {
818 return termsOfUseURL;
819 }
820
821 /**
822 * Set the attribution text
823 * @param text The text
824 * @see #getAttributionText(int, ICoordinate, ICoordinate)
825 */
826 public void setAttributionText(String text) {
827 attributionText = text;
828 }
829
830 /**
831 * Set the attribution image
832 * @param url The url of the image.
833 * @see #getAttributionImageURL()
834 */
835 public void setAttributionImageURL(String url) {
836 attributionImageURL = url;
837 }
838
839 /**
840 * Set the image for the attribution
841 * @param res The image resource
842 * @see #getAttributionImage()
843 */
844 public void setAttributionImage(String res) {
845 attributionImage = res;
846 }
847
848 /**
849 * Sets the URL the attribution should link to.
850 * @param url The url.
851 * @see #getAttributionLinkURL()
852 */
853 public void setAttributionLinkURL(String url) {
854 attributionLinkURL = url;
855 }
856
857 /**
858 * Sets the permission reference URL.
859 * @param url The url.
860 * @see #getPermissionReferenceURL()
861 * @since 11975
862 */
863 public void setPermissionReferenceURL(String url) {
864 permissionReferenceURL = url;
865 }
866
867 /**
868 * Sets the text to display to the user as terms of use.
869 * @param text The text
870 * @see #getTermsOfUseText()
871 */
872 public void setTermsOfUseText(String text) {
873 termsOfUseText = text;
874 }
875
876 /**
877 * Sets a url that links to the terms of use text.
878 * @param text The url.
879 * @see #getTermsOfUseURL()
880 */
881 public void setTermsOfUseURL(String text) {
882 termsOfUseURL = text;
883 }
884
885 /**
886 * Sets the extended URL of this entry.
887 * @param url Entry extended URL containing in addition of service URL, its type and min/max zoom info
888 */
889 public void setExtendedUrl(String url) {
890 CheckParameterUtil.ensureParameterNotNull(url);
891
892 // Default imagery type is WMS
893 this.url = url;
894 this.imageryType = ImageryType.WMS;
895
896 defaultMaxZoom = 0;
897 defaultMinZoom = 0;
898 for (ImageryType type : ImageryType.values()) {
899 Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)\\])?:(.*)").matcher(url);
900 if (m.matches()) {
901 this.url = m.group(3);
902 this.imageryType = type;
903 if (m.group(2) != null) {
904 defaultMaxZoom = Integer.parseInt(m.group(2));
905 }
906 if (m.group(1) != null) {
907 defaultMinZoom = Integer.parseInt(m.group(1));
908 }
909 break;
910 }
911 }
912
913 if (serverProjections.isEmpty()) {
914 serverProjections = new ArrayList<>();
915 Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)\\}.*").matcher(url.toUpperCase(Locale.ENGLISH));
916 if (m.matches()) {
917 for (String p : m.group(1).split(",")) {
918 serverProjections.add(p);
919 }
920 }
921 }
922 }
923
924 /**
925 * Returns the entry name.
926 * @return The entry name
927 * @since 6968
928 */
929 public String getOriginalName() {
930 return this.origName != null ? this.origName : this.name;
931 }
932
933 /**
934 * Sets the entry name and handle translation.
935 * @param language The used language
936 * @param name The entry name
937 * @since 8091
938 */
939 public void setName(String language, String name) {
940 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
941 if (LanguageInfo.isBetterLanguage(langName, language)) {
942 this.name = isdefault ? tr(name) : name;
943 this.langName = language;
944 }
945 if (origName == null || isdefault) {
946 this.origName = name;
947 }
948 }
949
950 /**
951 * Store the id of this info to the preferences and clear it afterwards.
952 */
953 public void clearId() {
954 if (this.id != null) {
955 Collection<String> newAddedIds = new TreeSet<>(Config.getPref().getList("imagery.layers.addedIds"));
956 newAddedIds.add(this.id);
957 Config.getPref().putList("imagery.layers.addedIds", new ArrayList<>(newAddedIds));
958 }
959 setId(null);
960 }
961
962 /**
963 * Determines if this entry is enabled by default.
964 * @return {@code true} if this entry is enabled by default, {@code false} otherwise
965 */
966 public boolean isDefaultEntry() {
967 return defaultEntry;
968 }
969
970 /**
971 * Sets the default state of this entry.
972 * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
973 */
974 public void setDefaultEntry(boolean defaultEntry) {
975 this.defaultEntry = defaultEntry;
976 }
977
978 /**
979 * Gets the pixel per degree value
980 * @return The ppd value.
981 */
982 public double getPixelPerDegree() {
983 return this.pixelPerDegree;
984 }
985
986 /**
987 * Returns the maximum zoom level.
988 * @return The maximum zoom level
989 */
990 @Override
991 public int getMaxZoom() {
992 return this.defaultMaxZoom;
993 }
994
995 /**
996 * Returns the minimum zoom level.
997 * @return The minimum zoom level
998 */
999 @Override
1000 public int getMinZoom() {
1001 return this.defaultMinZoom;
1002 }
1003
1004 /**
1005 * Returns the description text when existing.
1006 * @return The description
1007 * @since 8065
1008 */
1009 public String getDescription() {
1010 return this.description;
1011 }
1012
1013 /**
1014 * Sets the description text when existing.
1015 * @param language The used language
1016 * @param description the imagery description text
1017 * @since 8091
1018 */
1019 public void setDescription(String language, String description) {
1020 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
1021 if (LanguageInfo.isBetterLanguage(langDescription, language)) {
1022 this.description = isdefault ? tr(description) : description;
1023 this.langDescription = language;
1024 }
1025 }
1026
1027 /**
1028 * Return the sorted list of activated Imagery IDs.
1029 * @return sorted list of activated Imagery IDs
1030 * @since 13536
1031 */
1032 public static Collection<String> getActiveIds() {
1033 ArrayList<String> ids = new ArrayList<>();
1034 IPreferences pref = Config.getPref();
1035 if (pref != null) {
1036 List<ImageryPreferenceEntry> entries = StructUtils.getListOfStructs(
1037 pref, "imagery.entries", null, ImageryPreferenceEntry.class);
1038 if (entries != null) {
1039 for (ImageryPreferenceEntry prefEntry : entries) {
1040 if (prefEntry.id != null && !prefEntry.id.isEmpty())
1041 ids.add(prefEntry.id);
1042 }
1043 Collections.sort(ids);
1044 }
1045 }
1046 return ids;
1047 }
1048
1049 /**
1050 * Returns a tool tip text for display.
1051 * @return The text
1052 * @since 8065
1053 */
1054 public String getToolTipText() {
1055 StringBuilder res = new StringBuilder(getName());
1056 boolean html = false;
1057 String dateStr = getDate();
1058 if (dateStr != null && !dateStr.isEmpty()) {
1059 res.append("<br>").append(tr("Date of imagery: {0}", dateStr));
1060 html = true;
1061 }
1062 if (category != null && category.getDescription() != null) {
1063 res.append("<br>").append(tr("Imagery category: {0}", category.getDescription()));
1064 html = true;
1065 }
1066 if (bestMarked) {
1067 res.append("<br>").append(tr("This imagery is marked as best in this region in other editors."));
1068 html = true;
1069 }
1070 if (overlay) {
1071 res.append("<br>").append(tr("This imagery is an overlay."));
1072 html = true;
1073 }
1074 String desc = getDescription();
1075 if (desc != null && !desc.isEmpty()) {
1076 res.append("<br>").append(Utils.escapeReservedCharactersHTML(desc));
1077 html = true;
1078 }
1079 if (html) {
1080 res.insert(0, "<html>").append("</html>");
1081 }
1082 return res.toString();
1083 }
1084
1085 /**
1086 * Returns the EULA acceptance URL, if any.
1087 * @return The URL to an EULA text that has to be accepted before use, or {@code null}
1088 */
1089 public String getEulaAcceptanceRequired() {
1090 return eulaAcceptanceRequired;
1091 }
1092
1093 /**
1094 * Sets the EULA acceptance URL.
1095 * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
1096 */
1097 public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
1098 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
1099 }
1100
1101 /**
1102 * Returns the ISO 3166-1-alpha-2 country code.
1103 * @return The country code (2 letters)
1104 */
1105 public String getCountryCode() {
1106 return countryCode;
1107 }
1108
1109 /**
1110 * Sets the ISO 3166-1-alpha-2 country code.
1111 * @param countryCode The country code (2 letters)
1112 */
1113 public void setCountryCode(String countryCode) {
1114 this.countryCode = countryCode;
1115 }
1116
1117 /**
1118 * Returns the date information.
1119 * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where
1120 * DD and MM as well as a second date are optional)
1121 * @since 11570
1122 */
1123 public String getDate() {
1124 return date;
1125 }
1126
1127 /**
1128 * Sets the date information.
1129 * @param date The date information
1130 * @since 11570
1131 */
1132 public void setDate(String date) {
1133 this.date = date;
1134 }
1135
1136 /**
1137 * Returns the entry icon.
1138 * @return The entry icon
1139 */
1140 public String getIcon() {
1141 return icon;
1142 }
1143
1144 /**
1145 * Sets the entry icon.
1146 * @param icon The entry icon
1147 */
1148 public void setIcon(String icon) {
1149 this.icon = icon;
1150 }
1151
1152 /**
1153 * Get the projections supported by the server. Only relevant for
1154 * WMS-type ImageryInfo at the moment.
1155 * @return null, if no projections have been specified; the list
1156 * of supported projections otherwise.
1157 */
1158 public List<String> getServerProjections() {
1159 return Collections.unmodifiableList(serverProjections);
1160 }
1161
1162 /**
1163 * Sets the list of collections the server supports
1164 * @param serverProjections The list of supported projections
1165 */
1166 public void setServerProjections(Collection<String> serverProjections) {
1167 CheckParameterUtil.ensureParameterNotNull(serverProjections, "serverProjections");
1168 this.serverProjections = new ArrayList<>(serverProjections);
1169 }
1170
1171 /**
1172 * Returns the extended URL, containing in addition of service URL, its type and min/max zoom info.
1173 * @return The extended URL
1174 */
1175 public String getExtendedUrl() {
1176 return imageryType.getTypeString() + (defaultMaxZoom != 0
1177 ? ('['+(defaultMinZoom != 0 ? (Integer.toString(defaultMinZoom) + ',') : "")+defaultMaxZoom+']') : "") + ':' + url;
1178 }
1179
1180 /**
1181 * Gets a unique toolbar key to store this layer as toolbar item
1182 * @return The kay.
1183 */
1184 public String getToolbarName() {
1185 String res = name;
1186 if (pixelPerDegree != 0) {
1187 res += "#PPD="+pixelPerDegree;
1188 }
1189 return res;
1190 }
1191
1192 /**
1193 * Gets the name that should be displayed in the menu to add this imagery layer.
1194 * @return The text.
1195 */
1196 public String getMenuName() {
1197 String res = name;
1198 if (pixelPerDegree != 0) {
1199 res += " ("+pixelPerDegree+')';
1200 }
1201 return res;
1202 }
1203
1204 /**
1205 * Determines if this entry requires attribution.
1206 * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
1207 */
1208 public boolean hasAttribution() {
1209 return attributionText != null;
1210 }
1211
1212 /**
1213 * Copies attribution from another {@code ImageryInfo}.
1214 * @param i The other imagery info to get attribution from
1215 */
1216 public void copyAttribution(ImageryInfo i) {
1217 this.attributionImage = i.attributionImage;
1218 this.attributionImageURL = i.attributionImageURL;
1219 this.attributionText = i.attributionText;
1220 this.attributionLinkURL = i.attributionLinkURL;
1221 this.termsOfUseText = i.termsOfUseText;
1222 this.termsOfUseURL = i.termsOfUseURL;
1223 }
1224
1225 /**
1226 * Applies the attribution from this object to a tile source.
1227 * @param s The tile source
1228 */
1229 public void setAttribution(AbstractTileSource s) {
1230 if (attributionText != null) {
1231 if ("osm".equals(attributionText)) {
1232 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
1233 } else {
1234 s.setAttributionText(attributionText);
1235 }
1236 }
1237 if (attributionLinkURL != null) {
1238 if ("osm".equals(attributionLinkURL)) {
1239 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
1240 } else {
1241 s.setAttributionLinkURL(attributionLinkURL);
1242 }
1243 }
1244 if (attributionImage != null) {
1245 ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
1246 if (i != null) {
1247 s.setAttributionImage(i.getImage());
1248 }
1249 }
1250 if (attributionImageURL != null) {
1251 s.setAttributionImageURL(attributionImageURL);
1252 }
1253 if (termsOfUseText != null) {
1254 s.setTermsOfUseText(termsOfUseText);
1255 }
1256 if (termsOfUseURL != null) {
1257 if ("osm".equals(termsOfUseURL)) {
1258 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
1259 } else {
1260 s.setTermsOfUseURL(termsOfUseURL);
1261 }
1262 }
1263 }
1264
1265 /**
1266 * Returns the imagery type.
1267 * @return The imagery type
1268 */
1269 public ImageryType getImageryType() {
1270 return imageryType;
1271 }
1272
1273 /**
1274 * Sets the imagery type.
1275 * @param imageryType The imagery type
1276 */
1277 public void setImageryType(ImageryType imageryType) {
1278 this.imageryType = imageryType;
1279 }
1280
1281 /**
1282 * Returns the imagery category.
1283 * @return The imagery category
1284 * @since 13792
1285 */
1286 public ImageryCategory getImageryCategory() {
1287 return category;
1288 }
1289
1290 /**
1291 * Sets the imagery category.
1292 * @param category The imagery category
1293 * @since 13792
1294 */
1295 public void setImageryCategory(ImageryCategory category) {
1296 this.category = category;
1297 }
1298
1299 /**
1300 * Returns the imagery category original string (don't use except for error checks).
1301 * @return The imagery category original string
1302 * @since 13792
1303 */
1304 public String getImageryCategoryOriginalString() {
1305 return categoryOriginalString;
1306 }
1307
1308 /**
1309 * Sets the imagery category original string (don't use except for error checks).
1310 * @param categoryOriginalString The imagery category original string
1311 * @since 13792
1312 */
1313 public void setImageryCategoryOriginalString(String categoryOriginalString) {
1314 this.categoryOriginalString = categoryOriginalString;
1315 }
1316
1317 /**
1318 * Returns true if this layer's URL is matched by one of the regular
1319 * expressions kept by the current OsmApi instance.
1320 * @return {@code true} is this entry is blacklisted, {@code false} otherwise
1321 */
1322 public boolean isBlacklisted() {
1323 Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
1324 return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
1325 }
1326
1327 /**
1328 * Sets the map of &lt;header name, header value&gt; that if any of this header
1329 * will be returned, then this tile will be treated as "no tile at this zoom level"
1330 *
1331 * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
1332 * @since 9613
1333 */
1334 public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
1335 if (noTileHeaders == null || noTileHeaders.isEmpty()) {
1336 this.noTileHeaders = null;
1337 } else {
1338 this.noTileHeaders = noTileHeaders.toMap();
1339 }
1340 }
1341
1342 @Override
1343 public Map<String, Set<String>> getNoTileHeaders() {
1344 return noTileHeaders;
1345 }
1346
1347 /**
1348 * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
1349 * will be returned, then this tile will be treated as "no tile at this zoom level"
1350 *
1351 * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
1352 * @since 9613
1353 */
1354 public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
1355 if (noTileChecksums == null || noTileChecksums.isEmpty()) {
1356 this.noTileChecksums = null;
1357 } else {
1358 this.noTileChecksums = noTileChecksums.toMap();
1359 }
1360 }
1361
1362 @Override
1363 public Map<String, Set<String>> getNoTileChecksums() {
1364 return noTileChecksums;
1365 }
1366
1367 /**
1368 * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
1369 * be moved to metadata
1370 *
1371 * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
1372 * @since 8418
1373 */
1374 public void setMetadataHeaders(Map<String, String> metadataHeaders) {
1375 if (metadataHeaders == null || metadataHeaders.isEmpty()) {
1376 this.metadataHeaders = null;
1377 } else {
1378 this.metadataHeaders = metadataHeaders;
1379 }
1380 }
1381
1382 /**
1383 * Gets the flag if the georeference is valid.
1384 * @return <code>true</code> if it is valid.
1385 */
1386 public boolean isGeoreferenceValid() {
1387 return isGeoreferenceValid;
1388 }
1389
1390 /**
1391 * Sets an indicator that the georeference is valid
1392 * @param isGeoreferenceValid <code>true</code> if it is marked as valid.
1393 */
1394 public void setGeoreferenceValid(boolean isGeoreferenceValid) {
1395 this.isGeoreferenceValid = isGeoreferenceValid;
1396 }
1397
1398 /**
1399 * Returns the status of "best" marked status in other editors.
1400 * @return <code>true</code> if it is marked as best.
1401 * @since 11575
1402 */
1403 public boolean isBestMarked() {
1404 return bestMarked;
1405 }
1406
1407 /**
1408 * Returns the overlay indication.
1409 * @return <code>true</code> if it is an overlay.
1410 * @since 13536
1411 */
1412 public boolean isOverlay() {
1413 return overlay;
1414 }
1415
1416 /**
1417 * Sets an indicator that in other editors it is marked as best imagery
1418 * @param bestMarked <code>true</code> if it is marked as best in other editors.
1419 * @since 11575
1420 */
1421 public void setBestMarked(boolean bestMarked) {
1422 this.bestMarked = bestMarked;
1423 }
1424
1425 /**
1426 * Sets overlay indication
1427 * @param overlay <code>true</code> if it is an overlay.
1428 * @since 13536
1429 */
1430 public void setOverlay(boolean overlay) {
1431 this.overlay = overlay;
1432 }
1433
1434 /**
1435 * Adds an old Id.
1436 *
1437 * @param id the Id to be added
1438 * @since 13536
1439 */
1440 public void addOldId(String id) {
1441 if (oldIds == null) {
1442 oldIds = new ArrayList<>();
1443 }
1444 oldIds.add(id);
1445 }
1446
1447 /**
1448 * Get old Ids.
1449 *
1450 * @return collection of ids
1451 * @since 13536
1452 */
1453 public Collection<String> getOldIds() {
1454 return oldIds;
1455 }
1456
1457 /**
1458 * Adds a mirror entry. Mirror entries are completed with the data from the master entry
1459 * and only describe another method to access identical data.
1460 *
1461 * @param entry the mirror to be added
1462 * @since 9658
1463 */
1464 public void addMirror(ImageryInfo entry) {
1465 if (mirrors == null) {
1466 mirrors = new ArrayList<>();
1467 }
1468 mirrors.add(entry);
1469 }
1470
1471 /**
1472 * Returns the mirror entries. Entries are completed with master entry data.
1473 *
1474 * @return the list of mirrors
1475 * @since 9658
1476 */
1477 public List<ImageryInfo> getMirrors() {
1478 List<ImageryInfo> l = new ArrayList<>();
1479 if (mirrors != null) {
1480 int num = 1;
1481 for (ImageryInfo i : mirrors) {
1482 ImageryInfo n = new ImageryInfo(this);
1483 if (i.defaultMaxZoom != 0) {
1484 n.defaultMaxZoom = i.defaultMaxZoom;
1485 }
1486 if (i.defaultMinZoom != 0) {
1487 n.defaultMinZoom = i.defaultMinZoom;
1488 }
1489 n.setServerProjections(i.getServerProjections());
1490 n.url = i.url;
1491 n.imageryType = i.imageryType;
1492 if (i.getTileSize() != 0) {
1493 n.setTileSize(i.getTileSize());
1494 }
1495 if (n.id != null) {
1496 n.id = n.id + "_mirror"+num;
1497 }
1498 if (num > 1) {
1499 n.name = tr("{0} mirror server {1}", n.name, num);
1500 if (n.origName != null) {
1501 n.origName += " mirror server " + num;
1502 }
1503 } else {
1504 n.name = tr("{0} mirror server", n.name);
1505 if (n.origName != null) {
1506 n.origName += " mirror server";
1507 }
1508 }
1509 l.add(n);
1510 ++num;
1511 }
1512 }
1513 return l;
1514 }
1515
1516 /**
1517 * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)
1518 * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer
1519 * to work on
1520 * @return Collection of the layer names
1521 */
1522 public List<DefaultLayer> getDefaultLayers() {
1523 return defaultLayers;
1524 }
1525
1526 /**
1527 * Sets the default layers that user will work with
1528 * @param layers set the list of default layers
1529 */
1530 public void setDefaultLayers(List<DefaultLayer> layers) {
1531 this.defaultLayers = layers;
1532 }
1533
1534 /**
1535 * Returns custom HTTP headers that should be sent with request towards imagery provider
1536 * @return headers
1537 */
1538 public Map<String, String> getCustomHttpHeaders() {
1539 if (customHttpHeaders == null) {
1540 return Collections.emptyMap();
1541 }
1542 return customHttpHeaders;
1543 }
1544
1545 /**
1546 * Sets custom HTTP headers that should be sent with request towards imagery provider
1547 * @param customHttpHeaders http headers
1548 */
1549 public void setCustomHttpHeaders(Map<String, String> customHttpHeaders) {
1550 this.customHttpHeaders = customHttpHeaders;
1551 }
1552
1553 /**
1554 * Determines if this imagery should be transparent.
1555 * @return should this imagery be transparent
1556 */
1557 public boolean isTransparent() {
1558 return transparent;
1559 }
1560
1561 /**
1562 * Sets whether imagery should be transparent.
1563 * @param transparent set to true if imagery should be transparent
1564 */
1565 public void setTransparent(boolean transparent) {
1566 this.transparent = transparent;
1567 }
1568
1569 /**
1570 * Returns minimum tile expiration in seconds.
1571 * @return minimum tile expiration in seconds
1572 */
1573 public int getMinimumTileExpire() {
1574 return minimumTileExpire;
1575 }
1576
1577 /**
1578 * Sets minimum tile expiration in seconds.
1579 * @param minimumTileExpire minimum tile expiration in seconds
1580 */
1581 public void setMinimumTileExpire(int minimumTileExpire) {
1582 this.minimumTileExpire = minimumTileExpire;
1583 }
1584
1585 /**
1586 * Get a string representation of this imagery info suitable for the {@code source} changeset tag.
1587 * @return English name, if known
1588 * @since 13890
1589 */
1590 public String getSourceName() {
1591 if (ImageryType.BING == getImageryType()) {
1592 return "Bing";
1593 } else {
1594 if (id != null) {
1595 // Retrieve english name, unfortunately not saved in preferences
1596 Optional<ImageryInfo> infoEn = ImageryLayerInfo.allDefaultLayers.stream().filter(x -> id.equals(x.getId())).findAny();
1597 if (infoEn.isPresent()) {
1598 return infoEn.get().getOriginalName();
1599 }
1600 }
1601 return getOriginalName();
1602 }
1603 }
1604}
Note: See TracBrowser for help on using the repository browser.