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

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

see #16301 - add category icons in imagery preferences

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