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

Last change on this file since 13792 was 13792, checked in by stoecker, 6 years ago

fix #16103 - add map type definitions

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