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

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

fix #13264 - more lenient TMS url regex to allow - zoom separator

  • Property svn:eol-style set to native
File size: 37.8 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.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.Collections;
11import java.util.List;
12import java.util.Locale;
13import java.util.Map;
14import java.util.Objects;
15import java.util.Set;
16import java.util.TreeSet;
17import java.util.regex.Matcher;
18import java.util.regex.Pattern;
19
20import javax.swing.ImageIcon;
21
22import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
23import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
24import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
25import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
26import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.data.Bounds;
29import org.openstreetmap.josm.data.Preferences.pref;
30import org.openstreetmap.josm.io.Capabilities;
31import org.openstreetmap.josm.io.OsmApi;
32import org.openstreetmap.josm.tools.CheckParameterUtil;
33import org.openstreetmap.josm.tools.ImageProvider;
34import org.openstreetmap.josm.tools.LanguageInfo;
35import org.openstreetmap.josm.tools.MultiMap;
36
37/**
38 * Class that stores info about an image background layer.
39 *
40 * @author Frederik Ramm
41 */
42public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInfo>, Attributed {
43
44 /**
45 * Type of imagery entry.
46 */
47 public enum ImageryType {
48 /** A WMS (Web Map Service) entry. **/
49 WMS("wms"),
50 /** A TMS (Tile Map Service) entry. **/
51 TMS("tms"),
52 /** An HTML proxy (previously used for Yahoo imagery) entry. **/
53 HTML("html"),
54 /** TMS entry for Microsoft Bing. */
55 BING("bing"),
56 /** TMS entry for Russian company <a href="https://wiki.openstreetmap.org/wiki/WikiProject_Russia/kosmosnimki">ScanEx</a>. **/
57 SCANEX("scanex"),
58 /** A WMS endpoint entry only stores the WMS server info, without layer, which are chosen later by the user. **/
59 WMS_ENDPOINT("wms_endpoint"),
60 /** WMTS stores GetCapabilities URL. Does not store any information about the layer **/
61 WMTS("wmts");
62
63
64 private final String typeString;
65
66 ImageryType(String urlString) {
67 this.typeString = urlString;
68 }
69
70 /**
71 * Returns the unique string identifying this type.
72 * @return the unique string identifying this type
73 * @since 6690
74 */
75 public final String getTypeString() {
76 return typeString;
77 }
78
79 /**
80 * Returns the imagery type from the given type string.
81 * @param s The type string
82 * @return the imagery type matching the given type string
83 */
84 public static ImageryType fromString(String s) {
85 for (ImageryType type : ImageryType.values()) {
86 if (type.getTypeString().equals(s)) {
87 return type;
88 }
89 }
90 return null;
91 }
92 }
93
94 /**
95 * Multi-polygon bounds for imagery backgrounds.
96 * Used to display imagery coverage in preferences and to determine relevant imagery entries based on edit location.
97 */
98 public static class ImageryBounds extends Bounds {
99
100 /**
101 * Constructs a new {@code ImageryBounds} from string.
102 * @param asString The string containing the list of shapes defining this bounds
103 * @param separator The shape separator in the given string, usually a comma
104 */
105 public ImageryBounds(String asString, String separator) {
106 super(asString, separator);
107 }
108
109 private List<Shape> shapes = new ArrayList<>();
110
111 /**
112 * Adds a new shape to this bounds.
113 * @param shape The shape to add
114 */
115 public final void addShape(Shape shape) {
116 this.shapes.add(shape);
117 }
118
119 /**
120 * Sets the list of shapes defining this bounds.
121 * @param shapes The list of shapes defining this bounds.
122 */
123 public final void setShapes(List<Shape> shapes) {
124 this.shapes = shapes;
125 }
126
127 /**
128 * Returns the list of shapes defining this bounds.
129 * @return The list of shapes defining this bounds
130 */
131 public final List<Shape> getShapes() {
132 return shapes;
133 }
134
135 @Override
136 public int hashCode() {
137 return Objects.hash(super.hashCode(), shapes);
138 }
139
140 @Override
141 public boolean equals(Object o) {
142 if (this == o) return true;
143 if (o == null || getClass() != o.getClass()) return false;
144 if (!super.equals(o)) return false;
145 ImageryBounds that = (ImageryBounds) o;
146 return Objects.equals(shapes, that.shapes);
147 }
148 }
149
150 /** original name of the imagery entry in case of translation call, for multiple languages English when possible */
151 private String origName;
152 /** (original) language of the translated name entry */
153 private String langName;
154 /** whether this is a entry activated by default or not */
155 private boolean defaultEntry;
156 /** The data part of HTTP cookies header in case the service requires cookies to work */
157 private String cookies;
158 /** Whether this service requires a explicit EULA acceptance before it can be activated */
159 private String eulaAcceptanceRequired;
160 /** type of the imagery servics - WMS, TMS, ... */
161 private ImageryType imageryType = ImageryType.WMS;
162 private double pixelPerDegree;
163 /** maximum zoom level for TMS imagery */
164 private int defaultMaxZoom;
165 /** minimum zoom level for TMS imagery */
166 private int defaultMinZoom;
167 /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */
168 private ImageryBounds bounds;
169 /** projections supported by WMS servers */
170 private List<String> serverProjections = Collections.emptyList();
171 /** description of the imagery entry, should contain notes what type of data it is */
172 private String description;
173 /** language of the description entry */
174 private String langDescription;
175 /** Text of a text attribution displayed when using the imagery */
176 private String attributionText;
177 /** Link behing the text attribution displayed when using the imagery */
178 private String attributionLinkURL;
179 /** Image of a graphical attribution displayed when using the imagery */
180 private String attributionImage;
181 /** Link behind the graphical attribution displayed when using the imagery */
182 private String attributionImageURL;
183 /** Text with usage terms displayed when using the imagery */
184 private String termsOfUseText;
185 /** Link behind the text with usage terms displayed when using the imagery */
186 private String termsOfUseURL;
187 /** country code of the imagery (for country specific imagery) */
188 private String countryCode = "";
189 /** mirrors of different type for this entry */
190 private List<ImageryInfo> mirrors;
191 /** icon used in menu */
192 private String icon;
193 private boolean isGeoreferenceValid;
194 private boolean isEpsg4326To3857Supported;
195 // when adding a field, also adapt the ImageryInfo(ImageryInfo)
196 // and ImageryInfo(ImageryPreferenceEntry) constructor, equals method, and ImageryPreferenceEntry
197
198 /**
199 * Auxiliary class to save an {@link ImageryInfo} object in the preferences.
200 */
201 public static class ImageryPreferenceEntry {
202 @pref String name;
203 @pref String id;
204 @pref String type;
205 @pref String url;
206 @pref double pixel_per_eastnorth;
207 @pref String eula;
208 @pref String attribution_text;
209 @pref String attribution_url;
210 @pref String logo_image;
211 @pref String logo_url;
212 @pref String terms_of_use_text;
213 @pref String terms_of_use_url;
214 @pref String country_code = "";
215 @pref int max_zoom;
216 @pref int min_zoom;
217 @pref String cookies;
218 @pref String bounds;
219 @pref String shapes;
220 @pref String projections;
221 @pref String icon;
222 @pref String description;
223 @pref MultiMap<String, String> noTileHeaders;
224 @pref MultiMap<String, String> noTileChecksums;
225 @pref int tileSize = -1;
226 @pref Map<String, String> metadataHeaders;
227 @pref boolean valid_georeference;
228 @pref boolean supports_epsg_4326_to_3857_conversion;
229
230 /**
231 * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
232 */
233 public ImageryPreferenceEntry() {
234 // Do nothing
235 }
236
237 /**
238 * Constructs a new {@code ImageryPreferenceEntry} from a given {@code ImageryInfo}.
239 * @param i The corresponding imagery info
240 */
241 public ImageryPreferenceEntry(ImageryInfo i) {
242 name = i.name;
243 id = i.id;
244 type = i.imageryType.getTypeString();
245 url = i.url;
246 pixel_per_eastnorth = i.pixelPerDegree;
247 eula = i.eulaAcceptanceRequired;
248 attribution_text = i.attributionText;
249 attribution_url = i.attributionLinkURL;
250 logo_image = i.attributionImage;
251 logo_url = i.attributionImageURL;
252 terms_of_use_text = i.termsOfUseText;
253 terms_of_use_url = i.termsOfUseURL;
254 country_code = i.countryCode;
255 max_zoom = i.defaultMaxZoom;
256 min_zoom = i.defaultMinZoom;
257 cookies = i.cookies;
258 icon = i.icon;
259 description = i.description;
260 if (i.bounds != null) {
261 bounds = i.bounds.encodeAsString(",");
262 StringBuilder shapesString = new StringBuilder();
263 for (Shape s : i.bounds.getShapes()) {
264 if (shapesString.length() > 0) {
265 shapesString.append(';');
266 }
267 shapesString.append(s.encodeAsString(","));
268 }
269 if (shapesString.length() > 0) {
270 shapes = shapesString.toString();
271 }
272 }
273 if (!i.serverProjections.isEmpty()) {
274 StringBuilder val = new StringBuilder();
275 for (String p : i.serverProjections) {
276 if (val.length() > 0) {
277 val.append(',');
278 }
279 val.append(p);
280 }
281 projections = val.toString();
282 }
283 if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
284 noTileHeaders = new MultiMap<>(i.noTileHeaders);
285 }
286
287 if (i.noTileChecksums != null && !i.noTileChecksums.isEmpty()) {
288 noTileChecksums = new MultiMap<>(i.noTileChecksums);
289 }
290
291 if (i.metadataHeaders != null && !i.metadataHeaders.isEmpty()) {
292 metadataHeaders = i.metadataHeaders;
293 }
294
295 tileSize = i.getTileSize();
296
297 valid_georeference = i.isGeoreferenceValid();
298 supports_epsg_4326_to_3857_conversion = i.isEpsg4326To3857Supported();
299 }
300
301 @Override
302 public String toString() {
303 StringBuilder s = new StringBuilder("ImageryPreferenceEntry [name=").append(name);
304 if (id != null) {
305 s.append(" id=").append(id);
306 }
307 s.append(']');
308 return s.toString();
309 }
310 }
311
312 /**
313 * Constructs a new WMS {@code ImageryInfo}.
314 */
315 public ImageryInfo() {
316 super();
317 }
318
319 /**
320 * Constructs a new WMS {@code ImageryInfo} with a given name.
321 * @param name The entry name
322 */
323 public ImageryInfo(String name) {
324 super(name);
325 }
326
327 /**
328 * Constructs a new WMS {@code ImageryInfo} with given name and extended URL.
329 * @param name The entry name
330 * @param url The entry extended URL
331 */
332 public ImageryInfo(String name, String url) {
333 this(name);
334 setExtendedUrl(url);
335 }
336
337 /**
338 * Constructs a new WMS {@code ImageryInfo} with given name, extended and EULA URLs.
339 * @param name The entry name
340 * @param url The entry URL
341 * @param eulaAcceptanceRequired The EULA URL
342 */
343 public ImageryInfo(String name, String url, String eulaAcceptanceRequired) {
344 this(name);
345 setExtendedUrl(url);
346 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
347 }
348
349 /**
350 * Constructs a new {@code ImageryInfo} with given name, url, extended and EULA URLs.
351 * @param name The entry name
352 * @param url The entry URL
353 * @param type The entry imagery type. If null, WMS will be used as default
354 * @param eulaAcceptanceRequired The EULA URL
355 * @param cookies The data part of HTTP cookies header in case the service requires cookies to work
356 * @throws IllegalArgumentException if type refers to an unknown imagery type
357 */
358 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies) {
359 this(name);
360 setExtendedUrl(url);
361 ImageryType t = ImageryType.fromString(type);
362 this.cookies = cookies;
363 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
364 if (t != null) {
365 this.imageryType = t;
366 } else if (type != null && !type.trim().isEmpty()) {
367 throw new IllegalArgumentException("unknown type: "+type);
368 }
369 }
370
371 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies, String id) {
372 this(name, url, type, eulaAcceptanceRequired, cookies);
373 setId(id);
374 }
375
376 /**
377 * Constructs a new {@code ImageryInfo} from an imagery preference entry.
378 * @param e The imagery preference entry
379 */
380 public ImageryInfo(ImageryPreferenceEntry e) {
381 super(e.name, e.url, e.id);
382 CheckParameterUtil.ensureParameterNotNull(e.name, "name");
383 CheckParameterUtil.ensureParameterNotNull(e.url, "url");
384 description = e.description;
385 cookies = e.cookies;
386 eulaAcceptanceRequired = e.eula;
387 imageryType = ImageryType.fromString(e.type);
388 if (imageryType == null) throw new IllegalArgumentException("unknown type");
389 pixelPerDegree = e.pixel_per_eastnorth;
390 defaultMaxZoom = e.max_zoom;
391 defaultMinZoom = e.min_zoom;
392 if (e.bounds != null) {
393 bounds = new ImageryBounds(e.bounds, ",");
394 if (e.shapes != null) {
395 try {
396 for (String s : e.shapes.split(";")) {
397 bounds.addShape(new Shape(s, ","));
398 }
399 } catch (IllegalArgumentException ex) {
400 Main.warn(ex);
401 }
402 }
403 }
404 if (e.projections != null) {
405 serverProjections = Arrays.asList(e.projections.split(","));
406 }
407 attributionText = e.attribution_text;
408 attributionLinkURL = e.attribution_url;
409 attributionImage = e.logo_image;
410 attributionImageURL = e.logo_url;
411 termsOfUseText = e.terms_of_use_text;
412 termsOfUseURL = e.terms_of_use_url;
413 countryCode = e.country_code;
414 icon = e.icon;
415 if (e.noTileHeaders != null) {
416 noTileHeaders = e.noTileHeaders.toMap();
417 }
418 if (e.noTileChecksums != null) {
419 noTileChecksums = e.noTileChecksums.toMap();
420 }
421 setTileSize(e.tileSize);
422 metadataHeaders = e.metadataHeaders;
423 isEpsg4326To3857Supported = e.supports_epsg_4326_to_3857_conversion;
424 isGeoreferenceValid = e.valid_georeference;
425 }
426
427 /**
428 * Constructs a new {@code ImageryInfo} from an existing one.
429 * @param i The other imagery info
430 */
431 public ImageryInfo(ImageryInfo i) {
432 super(i.name, i.url, i.id);
433 this.defaultEntry = i.defaultEntry;
434 this.cookies = i.cookies;
435 this.eulaAcceptanceRequired = null;
436 this.imageryType = i.imageryType;
437 this.pixelPerDegree = i.pixelPerDegree;
438 this.defaultMaxZoom = i.defaultMaxZoom;
439 this.defaultMinZoom = i.defaultMinZoom;
440 this.bounds = i.bounds;
441 this.serverProjections = i.serverProjections;
442 this.attributionText = i.attributionText;
443 this.attributionLinkURL = i.attributionLinkURL;
444 this.attributionImage = i.attributionImage;
445 this.attributionImageURL = i.attributionImageURL;
446 this.termsOfUseText = i.termsOfUseText;
447 this.termsOfUseURL = i.termsOfUseURL;
448 this.countryCode = i.countryCode;
449 this.icon = i.icon;
450 this.description = i.description;
451 this.noTileHeaders = i.noTileHeaders;
452 this.noTileChecksums = i.noTileChecksums;
453 this.metadataHeaders = i.metadataHeaders;
454 this.isEpsg4326To3857Supported = i.isEpsg4326To3857Supported;
455 this.isGeoreferenceValid = i.isGeoreferenceValid;
456 }
457
458 @Override
459 public int hashCode() {
460 return Objects.hash(url, imageryType);
461 }
462
463 /**
464 * Check if this object equals another ImageryInfo with respect to the properties
465 * that get written to the preference file.
466 *
467 * The field {@link #pixelPerDegree} is ignored.
468 *
469 * @param other the ImageryInfo object to compare to
470 * @return true if they are equal
471 */
472 public boolean equalsPref(ImageryInfo other) {
473 if (other == null) {
474 return false;
475 }
476
477 return
478 Objects.equals(this.name, other.name) &&
479 Objects.equals(this.id, other.id) &&
480 Objects.equals(this.url, other.url) &&
481 Objects.equals(this.cookies, other.cookies) &&
482 Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
483 Objects.equals(this.imageryType, other.imageryType) &&
484 Objects.equals(this.defaultMaxZoom, other.defaultMaxZoom) &&
485 Objects.equals(this.defaultMinZoom, other.defaultMinZoom) &&
486 Objects.equals(this.bounds, other.bounds) &&
487 Objects.equals(this.serverProjections, other.serverProjections) &&
488 Objects.equals(this.attributionText, other.attributionText) &&
489 Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
490 Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
491 Objects.equals(this.attributionImage, other.attributionImage) &&
492 Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
493 Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
494 Objects.equals(this.countryCode, other.countryCode) &&
495 Objects.equals(this.icon, other.icon) &&
496 Objects.equals(this.description, other.description) &&
497 Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
498 Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
499 Objects.equals(this.metadataHeaders, other.metadataHeaders);
500 }
501
502 @Override
503 public boolean equals(Object o) {
504 if (this == o) return true;
505 if (o == null || getClass() != o.getClass()) return false;
506 ImageryInfo that = (ImageryInfo) o;
507 return imageryType == that.imageryType && Objects.equals(url, that.url);
508 }
509
510 @Override
511 public String toString() {
512 return "ImageryInfo{" +
513 "name='" + name + '\'' +
514 ", countryCode='" + countryCode + '\'' +
515 ", url='" + url + '\'' +
516 ", imageryType=" + imageryType +
517 '}';
518 }
519
520 @Override
521 public int compareTo(ImageryInfo in) {
522 int i = countryCode.compareTo(in.countryCode);
523 if (i == 0) {
524 i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
525 }
526 if (i == 0) {
527 i = url.compareTo(in.url);
528 }
529 if (i == 0) {
530 i = Double.compare(pixelPerDegree, in.pixelPerDegree);
531 }
532 return i;
533 }
534
535 public boolean equalsBaseValues(ImageryInfo in) {
536 return url.equals(in.url);
537 }
538
539 /**
540 * Sets the pixel per degree value.
541 * @param ppd The ppd value
542 * @see #getPixelPerDegree()
543 */
544 public void setPixelPerDegree(double ppd) {
545 this.pixelPerDegree = ppd;
546 }
547
548 /**
549 * Sets the maximum zoom level.
550 * @param defaultMaxZoom The maximum zoom level
551 */
552 public void setDefaultMaxZoom(int defaultMaxZoom) {
553 this.defaultMaxZoom = defaultMaxZoom;
554 }
555
556 /**
557 * Sets the minimum zoom level.
558 * @param defaultMinZoom The minimum zoom level
559 */
560 public void setDefaultMinZoom(int defaultMinZoom) {
561 this.defaultMinZoom = defaultMinZoom;
562 }
563
564 /**
565 * Sets the imagery polygonial bounds.
566 * @param b The imagery bounds (non-rectangular)
567 */
568 public void setBounds(ImageryBounds b) {
569 this.bounds = b;
570 }
571
572 /**
573 * Returns the imagery polygonial bounds.
574 * @return The imagery bounds (non-rectangular)
575 */
576 public ImageryBounds getBounds() {
577 return bounds;
578 }
579
580 @Override
581 public boolean requiresAttribution() {
582 return attributionText != null || attributionImage != null || termsOfUseText != null || termsOfUseURL != null;
583 }
584
585 @Override
586 public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
587 return attributionText;
588 }
589
590 @Override
591 public String getAttributionLinkURL() {
592 return attributionLinkURL;
593 }
594
595 @Override
596 public Image getAttributionImage() {
597 ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
598 if (i != null) {
599 return i.getImage();
600 }
601 return null;
602 }
603
604 @Override
605 public String getAttributionImageURL() {
606 return attributionImageURL;
607 }
608
609 @Override
610 public String getTermsOfUseText() {
611 return termsOfUseText;
612 }
613
614 @Override
615 public String getTermsOfUseURL() {
616 return termsOfUseURL;
617 }
618
619 /**
620 * Set the attribution text
621 * @param text The text
622 * @see #getAttributionText(int, ICoordinate, ICoordinate)
623 */
624 public void setAttributionText(String text) {
625 attributionText = text;
626 }
627
628 /**
629 * Set the attribution image
630 * @param url The url of the image.
631 * @see #getAttributionImageURL()
632 */
633 public void setAttributionImageURL(String url) {
634 attributionImageURL = url;
635 }
636
637 /**
638 * Set the image for the attribution
639 * @param res The image resource
640 * @see #getAttributionImage()
641 */
642 public void setAttributionImage(String res) {
643 attributionImage = res;
644 }
645
646 /**
647 * Sets the URL the attribution should link to.
648 * @param url The url.
649 * @see #getAttributionLinkURL()
650 */
651 public void setAttributionLinkURL(String url) {
652 attributionLinkURL = url;
653 }
654
655 /**
656 * Sets the text to display to the user as terms of use.
657 * @param text The text
658 * @see #getTermsOfUseText()
659 */
660 public void setTermsOfUseText(String text) {
661 termsOfUseText = text;
662 }
663
664 /**
665 * Sets a url that links to the terms of use text.
666 * @param text The url.
667 * @see #getTermsOfUseURL()
668 */
669 public void setTermsOfUseURL(String text) {
670 termsOfUseURL = text;
671 }
672
673 /**
674 * Sets the extended URL of this entry.
675 * @param url Entry extended URL containing in addition of service URL, its type and min/max zoom info
676 */
677 public void setExtendedUrl(String url) {
678 CheckParameterUtil.ensureParameterNotNull(url);
679
680 // Default imagery type is WMS
681 this.url = url;
682 this.imageryType = ImageryType.WMS;
683
684 defaultMaxZoom = 0;
685 defaultMinZoom = 0;
686 for (ImageryType type : ImageryType.values()) {
687 Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)\\])?:(.*)").matcher(url);
688 if (m.matches()) {
689 this.url = m.group(3);
690 this.imageryType = type;
691 if (m.group(2) != null) {
692 defaultMaxZoom = Integer.parseInt(m.group(2));
693 }
694 if (m.group(1) != null) {
695 defaultMinZoom = Integer.parseInt(m.group(1));
696 }
697 break;
698 }
699 }
700
701 if (serverProjections.isEmpty()) {
702 serverProjections = new ArrayList<>();
703 Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)\\}.*").matcher(url.toUpperCase(Locale.ENGLISH));
704 if (m.matches()) {
705 for (String p : m.group(1).split(",")) {
706 serverProjections.add(p);
707 }
708 }
709 }
710 }
711
712 /**
713 * Returns the entry name.
714 * @return The entry name
715 * @since 6968
716 */
717 public String getOriginalName() {
718 return this.origName != null ? this.origName : this.name;
719 }
720
721 /**
722 * Sets the entry name and handle translation.
723 * @param language The used language
724 * @param name The entry name
725 * @since 8091
726 */
727 public void setName(String language, String name) {
728 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
729 if (LanguageInfo.isBetterLanguage(langName, language)) {
730 this.name = isdefault ? tr(name) : name;
731 this.langName = language;
732 }
733 if (origName == null || isdefault) {
734 this.origName = name;
735 }
736 }
737
738 /**
739 * Store the id of this info to the preferences and clear it afterwards.
740 */
741 public void clearId() {
742 if (this.id != null) {
743 Collection<String> newAddedIds = new TreeSet<>(Main.pref.getCollection("imagery.layers.addedIds"));
744 newAddedIds.add(this.id);
745 Main.pref.putCollection("imagery.layers.addedIds", newAddedIds);
746 }
747 setId(null);
748 }
749
750 /**
751 * Determines if this entry is enabled by default.
752 * @return {@code true} if this entry is enabled by default, {@code false} otherwise
753 */
754 public boolean isDefaultEntry() {
755 return defaultEntry;
756 }
757
758 /**
759 * Sets the default state of this entry.
760 * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
761 */
762 public void setDefaultEntry(boolean defaultEntry) {
763 this.defaultEntry = defaultEntry;
764 }
765
766 /**
767 * Return the data part of HTTP cookies header in case the service requires cookies to work
768 * @return the cookie data part
769 */
770 @Override
771 public String getCookies() {
772 return this.cookies;
773 }
774
775 /**
776 * Gets the pixel per degree value
777 * @return The ppd value.
778 */
779 public double getPixelPerDegree() {
780 return this.pixelPerDegree;
781 }
782
783 /**
784 * Returns the maximum zoom level.
785 * @return The maximum zoom level
786 */
787 @Override
788 public int getMaxZoom() {
789 return this.defaultMaxZoom;
790 }
791
792 /**
793 * Returns the minimum zoom level.
794 * @return The minimum zoom level
795 */
796 @Override
797 public int getMinZoom() {
798 return this.defaultMinZoom;
799 }
800
801 /**
802 * Returns the description text when existing.
803 * @return The description
804 * @since 8065
805 */
806 public String getDescription() {
807 return this.description;
808 }
809
810 /**
811 * Sets the description text when existing.
812 * @param language The used language
813 * @param description the imagery description text
814 * @since 8091
815 */
816 public void setDescription(String language, String description) {
817 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
818 if (LanguageInfo.isBetterLanguage(langDescription, language)) {
819 this.description = isdefault ? tr(description) : description;
820 this.langDescription = language;
821 }
822 }
823
824 /**
825 * Returns a tool tip text for display.
826 * @return The text
827 * @since 8065
828 */
829 public String getToolTipText() {
830 String desc = getDescription();
831 if (desc != null && !desc.isEmpty()) {
832 return "<html>" + getName() + "<br>" + desc + "</html>";
833 }
834 return getName();
835 }
836
837 /**
838 * Returns the EULA acceptance URL, if any.
839 * @return The URL to an EULA text that has to be accepted before use, or {@code null}
840 */
841 public String getEulaAcceptanceRequired() {
842 return eulaAcceptanceRequired;
843 }
844
845 /**
846 * Sets the EULA acceptance URL.
847 * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
848 */
849 public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
850 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
851 }
852
853 /**
854 * Returns the ISO 3166-1-alpha-2 country code.
855 * @return The country code (2 letters)
856 */
857 public String getCountryCode() {
858 return countryCode;
859 }
860
861 /**
862 * Sets the ISO 3166-1-alpha-2 country code.
863 * @param countryCode The country code (2 letters)
864 */
865 public void setCountryCode(String countryCode) {
866 this.countryCode = countryCode;
867 }
868
869 /**
870 * Returns the entry icon.
871 * @return The entry icon
872 */
873 public String getIcon() {
874 return icon;
875 }
876
877 /**
878 * Sets the entry icon.
879 * @param icon The entry icon
880 */
881 public void setIcon(String icon) {
882 this.icon = icon;
883 }
884
885 /**
886 * Get the projections supported by the server. Only relevant for
887 * WMS-type ImageryInfo at the moment.
888 * @return null, if no projections have been specified; the list
889 * of supported projections otherwise.
890 */
891 public List<String> getServerProjections() {
892 return Collections.unmodifiableList(serverProjections);
893 }
894
895 /**
896 * Sets the list of collections the server supports
897 * @param serverProjections The list of supported projections
898 */
899 public void setServerProjections(Collection<String> serverProjections) {
900 CheckParameterUtil.ensureParameterNotNull(serverProjections, "serverProjections");
901 this.serverProjections = new ArrayList<>(serverProjections);
902 }
903
904 /**
905 * Returns the extended URL, containing in addition of service URL, its type and min/max zoom info.
906 * @return The extended URL
907 */
908 public String getExtendedUrl() {
909 return imageryType.getTypeString() + (defaultMaxZoom != 0
910 ? ('['+(defaultMinZoom != 0 ? (Integer.toString(defaultMinZoom) + ',') : "")+defaultMaxZoom+']') : "") + ':' + url;
911 }
912
913 /**
914 * Gets a unique toolbar key to store this layer as toolbar item
915 * @return The kay.
916 */
917 public String getToolbarName() {
918 String res = name;
919 if (pixelPerDegree != 0) {
920 res += "#PPD="+pixelPerDegree;
921 }
922 return res;
923 }
924
925 /**
926 * Gets the name that should be displayed in the menu to add this imagery layer.
927 * @return The text.
928 */
929 public String getMenuName() {
930 String res = name;
931 if (pixelPerDegree != 0) {
932 res += " ("+pixelPerDegree+')';
933 }
934 return res;
935 }
936
937 /**
938 * Determines if this entry requires attribution.
939 * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
940 */
941 public boolean hasAttribution() {
942 return attributionText != null;
943 }
944
945 /**
946 * Copies attribution from another {@code ImageryInfo}.
947 * @param i The other imagery info to get attribution from
948 */
949 public void copyAttribution(ImageryInfo i) {
950 this.attributionImage = i.attributionImage;
951 this.attributionImageURL = i.attributionImageURL;
952 this.attributionText = i.attributionText;
953 this.attributionLinkURL = i.attributionLinkURL;
954 this.termsOfUseText = i.termsOfUseText;
955 this.termsOfUseURL = i.termsOfUseURL;
956 }
957
958 /**
959 * Applies the attribution from this object to a tile source.
960 * @param s The tile source
961 */
962 public void setAttribution(AbstractTileSource s) {
963 if (attributionText != null) {
964 if ("osm".equals(attributionText)) {
965 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
966 } else {
967 s.setAttributionText(attributionText);
968 }
969 }
970 if (attributionLinkURL != null) {
971 if ("osm".equals(attributionLinkURL)) {
972 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
973 } else {
974 s.setAttributionLinkURL(attributionLinkURL);
975 }
976 }
977 if (attributionImage != null) {
978 ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
979 if (i != null) {
980 s.setAttributionImage(i.getImage());
981 }
982 }
983 if (attributionImageURL != null) {
984 s.setAttributionImageURL(attributionImageURL);
985 }
986 if (termsOfUseText != null) {
987 s.setTermsOfUseText(termsOfUseText);
988 }
989 if (termsOfUseURL != null) {
990 if ("osm".equals(termsOfUseURL)) {
991 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
992 } else {
993 s.setTermsOfUseURL(termsOfUseURL);
994 }
995 }
996 }
997
998 /**
999 * Returns the imagery type.
1000 * @return The imagery type
1001 */
1002 public ImageryType getImageryType() {
1003 return imageryType;
1004 }
1005
1006 /**
1007 * Sets the imagery type.
1008 * @param imageryType The imagery type
1009 */
1010 public void setImageryType(ImageryType imageryType) {
1011 this.imageryType = imageryType;
1012 }
1013
1014 /**
1015 * Returns true if this layer's URL is matched by one of the regular
1016 * expressions kept by the current OsmApi instance.
1017 * @return {@code true} is this entry is blacklisted, {@code false} otherwise
1018 */
1019 public boolean isBlacklisted() {
1020 Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
1021 return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
1022 }
1023
1024 /**
1025 * Sets the map of &lt;header name, header value&gt; that if any of this header
1026 * will be returned, then this tile will be treated as "no tile at this zoom level"
1027 *
1028 * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
1029 * @since 9613
1030 */
1031 public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
1032 if (noTileHeaders == null) {
1033 this.noTileHeaders = null;
1034 } else {
1035 this.noTileHeaders = noTileHeaders.toMap();
1036 }
1037 }
1038
1039 @Override
1040 public Map<String, Set<String>> getNoTileHeaders() {
1041 return noTileHeaders;
1042 }
1043
1044 /**
1045 * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
1046 * will be returned, then this tile will be treated as "no tile at this zoom level"
1047 *
1048 * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
1049 * @since 9613
1050 */
1051 public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
1052 if (noTileChecksums == null) {
1053 this.noTileChecksums = null;
1054 } else {
1055 this.noTileChecksums = noTileChecksums.toMap();
1056 }
1057 }
1058
1059 @Override
1060 public Map<String, Set<String>> getNoTileChecksums() {
1061 return noTileChecksums;
1062 }
1063
1064 /**
1065 * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
1066 * be moved to metadata
1067 *
1068 * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
1069 * @since 8418
1070 */
1071 public void setMetadataHeaders(Map<String, String> metadataHeaders) {
1072 this.metadataHeaders = metadataHeaders;
1073 }
1074
1075 /**
1076 * Gets the flag if epsg 4326 to 3857 is supported
1077 * @return The flag.
1078 */
1079 public boolean isEpsg4326To3857Supported() {
1080 return isEpsg4326To3857Supported;
1081 }
1082
1083 /**
1084 * Sets the flag that epsg 4326 to 3857 is supported
1085 * @param isEpsg4326To3857Supported The flag.
1086 */
1087 public void setEpsg4326To3857Supported(boolean isEpsg4326To3857Supported) {
1088 this.isEpsg4326To3857Supported = isEpsg4326To3857Supported;
1089 }
1090
1091 /**
1092 * Gets the flag if the georeference is valid.
1093 * @return <code>true</code> if it is valid.
1094 */
1095 public boolean isGeoreferenceValid() {
1096 return isGeoreferenceValid;
1097 }
1098
1099 /**
1100 * Sets an indicator that the georeference is valid
1101 * @param isGeoreferenceValid <code>true</code> if it is marked as valid.
1102 */
1103 public void setGeoreferenceValid(boolean isGeoreferenceValid) {
1104 this.isGeoreferenceValid = isGeoreferenceValid;
1105 }
1106
1107 /**
1108 * Adds a mirror entry. Mirror entries are completed with the data from the master entry
1109 * and only describe another method to access identical data.
1110 *
1111 * @param entry the mirror to be added
1112 * @since 9658
1113 */
1114 public void addMirror(ImageryInfo entry) {
1115 if (mirrors == null) {
1116 mirrors = new ArrayList<>();
1117 }
1118 mirrors.add(entry);
1119 }
1120
1121 /**
1122 * Returns the mirror entries. Entries are completed with master entry data.
1123 *
1124 * @return the list of mirrors
1125 * @since 9658
1126 */
1127 public List<ImageryInfo> getMirrors() {
1128 List<ImageryInfo> l = new ArrayList<>();
1129 if (mirrors != null) {
1130 for (ImageryInfo i : mirrors) {
1131 ImageryInfo n = new ImageryInfo(this);
1132 if (i.defaultMaxZoom != 0) {
1133 n.defaultMaxZoom = i.defaultMaxZoom;
1134 }
1135 if (i.defaultMinZoom != 0) {
1136 n.defaultMinZoom = i.defaultMinZoom;
1137 }
1138 n.setServerProjections(i.getServerProjections());
1139 n.url = i.url;
1140 n.imageryType = i.imageryType;
1141 if (i.getTileSize() != 0) {
1142 n.setTileSize(i.getTileSize());
1143 }
1144 l.add(n);
1145 }
1146 }
1147 return l;
1148 }
1149}
Note: See TracBrowser for help on using the repository browser.