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

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

checkstyle

  • Property svn:eol-style set to native
File size: 43.5 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;
19import java.util.stream.Collectors;
20
21import javax.swing.ImageIcon;
22
23import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
24import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
25import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
26import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
27import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
28import org.openstreetmap.josm.Main;
29import org.openstreetmap.josm.data.Bounds;
30import org.openstreetmap.josm.data.Preferences.pref;
31import org.openstreetmap.josm.io.Capabilities;
32import org.openstreetmap.josm.io.OsmApi;
33import org.openstreetmap.josm.tools.CheckParameterUtil;
34import org.openstreetmap.josm.tools.ImageProvider;
35import org.openstreetmap.josm.tools.LanguageInfo;
36import org.openstreetmap.josm.tools.MultiMap;
37import org.openstreetmap.josm.tools.Utils;
38
39/**
40 * Class that stores info about an image background layer.
41 *
42 * @author Frederik Ramm
43 */
44public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInfo>, Attributed {
45
46 /**
47 * Type of imagery entry.
48 */
49 public enum ImageryType {
50 /** A WMS (Web Map Service) entry. **/
51 WMS("wms"),
52 /** A TMS (Tile Map Service) entry. **/
53 TMS("tms"),
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 to a reference stating the permission for OSM usage */
178 private String permissionReferenceURL;
179 /** Link behind the text attribution displayed when using the imagery */
180 private String attributionLinkURL;
181 /** Image of a graphical attribution displayed when using the imagery */
182 private String attributionImage;
183 /** Link behind the graphical attribution displayed when using the imagery */
184 private String attributionImageURL;
185 /** Text with usage terms displayed when using the imagery */
186 private String termsOfUseText;
187 /** Link behind the text with usage terms displayed when using the imagery */
188 private String termsOfUseURL;
189 /** country code of the imagery (for country specific imagery) */
190 private String countryCode = "";
191 /**
192 * creation date of the imagery (in the form YYYY-MM-DD;YYYY-MM-DD, where
193 * DD and MM as well as a second date are optional)
194 * @since 11570
195 */
196 private String date;
197 /**
198 * marked as best in other editors
199 * @since 11575
200 */
201 private boolean bestMarked;
202 /** mirrors of different type for this entry */
203 private List<ImageryInfo> mirrors;
204 /** icon used in menu */
205 private String icon;
206 /** is the geo reference correct - don't offer offset handling */
207 private boolean isGeoreferenceValid;
208 /** which layers should be activated by default on layer addition. **/
209 private Collection<DefaultLayer> defaultLayers = Collections.emptyList();
210 // when adding a field, also adapt the ImageryInfo(ImageryInfo)
211 // and ImageryInfo(ImageryPreferenceEntry) constructor, equals method, and ImageryPreferenceEntry
212
213 /**
214 * Auxiliary class to save an {@link ImageryInfo} object in the preferences.
215 */
216 public static class ImageryPreferenceEntry {
217 @pref String name;
218 @pref String d;
219 @pref String id;
220 @pref String type;
221 @pref String url;
222 @pref double pixel_per_eastnorth;
223 @pref String eula;
224 @pref String attribution_text;
225 @pref String attribution_url;
226 @pref String permission_reference_url;
227 @pref String logo_image;
228 @pref String logo_url;
229 @pref String terms_of_use_text;
230 @pref String terms_of_use_url;
231 @pref String country_code = "";
232 @pref String date;
233 @pref int max_zoom;
234 @pref int min_zoom;
235 @pref String cookies;
236 @pref String bounds;
237 @pref String shapes;
238 @pref String projections;
239 @pref String icon;
240 @pref String description;
241 @pref MultiMap<String, String> noTileHeaders;
242 @pref MultiMap<String, String> noTileChecksums;
243 @pref int tileSize = -1;
244 @pref Map<String, String> metadataHeaders;
245 @pref boolean valid_georeference;
246 @pref boolean bestMarked;
247 // TODO: disabled until change of layers is implemented
248 // @pref String default_layers;
249
250 /**
251 * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
252 */
253 public ImageryPreferenceEntry() {
254 // Do nothing
255 }
256
257 /**
258 * Constructs a new {@code ImageryPreferenceEntry} from a given {@code ImageryInfo}.
259 * @param i The corresponding imagery info
260 */
261 public ImageryPreferenceEntry(ImageryInfo i) {
262 name = i.name;
263 id = i.id;
264 type = i.imageryType.getTypeString();
265 url = i.url;
266 pixel_per_eastnorth = i.pixelPerDegree;
267 eula = i.eulaAcceptanceRequired;
268 attribution_text = i.attributionText;
269 attribution_url = i.attributionLinkURL;
270 permission_reference_url = i.permissionReferenceURL;
271 date = i.date;
272 bestMarked = i.bestMarked;
273 logo_image = i.attributionImage;
274 logo_url = i.attributionImageURL;
275 terms_of_use_text = i.termsOfUseText;
276 terms_of_use_url = i.termsOfUseURL;
277 country_code = i.countryCode;
278 max_zoom = i.defaultMaxZoom;
279 min_zoom = i.defaultMinZoom;
280 cookies = i.cookies;
281 icon = i.icon;
282 description = i.description;
283 if (i.bounds != null) {
284 bounds = i.bounds.encodeAsString(",");
285 StringBuilder shapesString = new StringBuilder();
286 for (Shape s : i.bounds.getShapes()) {
287 if (shapesString.length() > 0) {
288 shapesString.append(';');
289 }
290 shapesString.append(s.encodeAsString(","));
291 }
292 if (shapesString.length() > 0) {
293 shapes = shapesString.toString();
294 }
295 }
296 projections = i.serverProjections.stream().collect(Collectors.joining(","));
297 if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
298 noTileHeaders = new MultiMap<>(i.noTileHeaders);
299 }
300
301 if (i.noTileChecksums != null && !i.noTileChecksums.isEmpty()) {
302 noTileChecksums = new MultiMap<>(i.noTileChecksums);
303 }
304
305 if (i.metadataHeaders != null && !i.metadataHeaders.isEmpty()) {
306 metadataHeaders = i.metadataHeaders;
307 }
308
309 tileSize = i.getTileSize();
310
311 valid_georeference = i.isGeoreferenceValid();
312 // TODO disabled until change of layers is implemented
313 // default_layers = i.defaultLayers.stream().collect(Collectors.joining(","));
314 }
315
316 @Override
317 public String toString() {
318 StringBuilder s = new StringBuilder("ImageryPreferenceEntry [name=").append(name);
319 if (id != null) {
320 s.append(" id=").append(id);
321 }
322 s.append(']');
323 return s.toString();
324 }
325 }
326
327 /**
328 * Constructs a new WMS {@code ImageryInfo}.
329 */
330 public ImageryInfo() {
331 super();
332 }
333
334 /**
335 * Constructs a new WMS {@code ImageryInfo} with a given name.
336 * @param name The entry name
337 */
338 public ImageryInfo(String name) {
339 super(name);
340 }
341
342 /**
343 * Constructs a new WMS {@code ImageryInfo} with given name and extended URL.
344 * @param name The entry name
345 * @param url The entry extended URL
346 */
347 public ImageryInfo(String name, String url) {
348 this(name);
349 setExtendedUrl(url);
350 }
351
352 /**
353 * Constructs a new WMS {@code ImageryInfo} with given name, extended and EULA URLs.
354 * @param name The entry name
355 * @param url The entry URL
356 * @param eulaAcceptanceRequired The EULA URL
357 */
358 public ImageryInfo(String name, String url, String eulaAcceptanceRequired) {
359 this(name);
360 setExtendedUrl(url);
361 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
362 }
363
364 /**
365 * Constructs a new {@code ImageryInfo} with given name, url, extended and EULA URLs.
366 * @param name The entry name
367 * @param url The entry URL
368 * @param type The entry imagery type. If null, WMS will be used as default
369 * @param eulaAcceptanceRequired The EULA URL
370 * @param cookies The data part of HTTP cookies header in case the service requires cookies to work
371 * @throws IllegalArgumentException if type refers to an unknown imagery type
372 */
373 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies) {
374 this(name);
375 setExtendedUrl(url);
376 ImageryType t = ImageryType.fromString(type);
377 this.cookies = cookies;
378 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
379 if (t != null) {
380 this.imageryType = t;
381 } else if (type != null && !type.isEmpty()) {
382 throw new IllegalArgumentException("unknown type: "+type);
383 }
384 }
385
386 /**
387 * Constructs a new {@code ImageryInfo} with given name, url, id, extended and EULA URLs.
388 * @param name The entry name
389 * @param url The entry URL
390 * @param type The entry imagery type. If null, WMS will be used as default
391 * @param eulaAcceptanceRequired The EULA URL
392 * @param cookies The data part of HTTP cookies header in case the service requires cookies to work
393 * @param id tile id
394 * @throws IllegalArgumentException if type refers to an unknown imagery type
395 */
396 public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies, String id) {
397 this(name, url, type, eulaAcceptanceRequired, cookies);
398 setId(id);
399 }
400
401 /**
402 * Constructs a new {@code ImageryInfo} from an imagery preference entry.
403 * @param e The imagery preference entry
404 */
405 public ImageryInfo(ImageryPreferenceEntry e) {
406 super(e.name, e.url, e.id);
407 CheckParameterUtil.ensureParameterNotNull(e.name, "name");
408 CheckParameterUtil.ensureParameterNotNull(e.url, "url");
409 description = e.description;
410 cookies = e.cookies;
411 eulaAcceptanceRequired = e.eula;
412 imageryType = ImageryType.fromString(e.type);
413 if (imageryType == null) throw new IllegalArgumentException("unknown type");
414 pixelPerDegree = e.pixel_per_eastnorth;
415 defaultMaxZoom = e.max_zoom;
416 defaultMinZoom = e.min_zoom;
417 if (e.bounds != null) {
418 bounds = new ImageryBounds(e.bounds, ",");
419 if (e.shapes != null) {
420 try {
421 for (String s : e.shapes.split(";")) {
422 bounds.addShape(new Shape(s, ","));
423 }
424 } catch (IllegalArgumentException ex) {
425 Main.warn(ex);
426 }
427 }
428 }
429 if (e.projections != null && !e.projections.isEmpty()) {
430 // split generates null element on empty string which gives one element Array[null]
431 serverProjections = Arrays.asList(e.projections.split(","));
432 }
433 attributionText = e.attribution_text;
434 attributionLinkURL = e.attribution_url;
435 permissionReferenceURL = e.permission_reference_url;
436 attributionImage = e.logo_image;
437 attributionImageURL = e.logo_url;
438 date = e.date;
439 bestMarked = e.bestMarked;
440 termsOfUseText = e.terms_of_use_text;
441 termsOfUseURL = e.terms_of_use_url;
442 countryCode = e.country_code;
443 icon = e.icon;
444 if (e.noTileHeaders != null) {
445 noTileHeaders = e.noTileHeaders.toMap();
446 }
447 if (e.noTileChecksums != null) {
448 noTileChecksums = e.noTileChecksums.toMap();
449 }
450 setTileSize(e.tileSize);
451 metadataHeaders = e.metadataHeaders;
452 isGeoreferenceValid = e.valid_georeference;
453 // TODO disabled until change of layers is implemented
454 // defaultLayers = Arrays.asList(e.default_layers.split(","));
455 }
456
457 /**
458 * Constructs a new {@code ImageryInfo} from an existing one.
459 * @param i The other imagery info
460 */
461 public ImageryInfo(ImageryInfo i) {
462 super(i.name, i.url, i.id);
463 this.origName = i.origName;
464 this.langName = i.langName;
465 this.bestMarked = i.bestMarked;
466 this.defaultEntry = i.defaultEntry;
467 this.cookies = i.cookies;
468 this.eulaAcceptanceRequired = null;
469 this.imageryType = i.imageryType;
470 this.pixelPerDegree = i.pixelPerDegree;
471 this.defaultMaxZoom = i.defaultMaxZoom;
472 this.defaultMinZoom = i.defaultMinZoom;
473 this.bounds = i.bounds;
474 this.serverProjections = i.serverProjections;
475 this.attributionText = i.attributionText;
476 this.attributionLinkURL = i.attributionLinkURL;
477 this.permissionReferenceURL = i.permissionReferenceURL;
478 this.attributionImage = i.attributionImage;
479 this.attributionImageURL = i.attributionImageURL;
480 this.termsOfUseText = i.termsOfUseText;
481 this.termsOfUseURL = i.termsOfUseURL;
482 this.countryCode = i.countryCode;
483 this.date = i.date;
484 this.icon = i.icon;
485 this.description = i.description;
486 this.noTileHeaders = i.noTileHeaders;
487 this.noTileChecksums = i.noTileChecksums;
488 this.metadataHeaders = i.metadataHeaders;
489 this.isGeoreferenceValid = i.isGeoreferenceValid;
490 this.defaultLayers = i.defaultLayers;
491 }
492
493 @Override
494 public int hashCode() {
495 return Objects.hash(url, imageryType);
496 }
497
498 /**
499 * Check if this object equals another ImageryInfo with respect to the properties
500 * that get written to the preference file.
501 *
502 * The field {@link #pixelPerDegree} is ignored.
503 *
504 * @param other the ImageryInfo object to compare to
505 * @return true if they are equal
506 */
507 public boolean equalsPref(ImageryInfo other) {
508 if (other == null) {
509 return false;
510 }
511
512 // CHECKSTYLE.OFF: BooleanExpressionComplexity
513 return
514 Objects.equals(this.name, other.name) &&
515 Objects.equals(this.id, other.id) &&
516 Objects.equals(this.url, other.url) &&
517 Objects.equals(this.bestMarked, other.bestMarked) &&
518 Objects.equals(this.isGeoreferenceValid, other.isGeoreferenceValid) &&
519 Objects.equals(this.cookies, other.cookies) &&
520 Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
521 Objects.equals(this.imageryType, other.imageryType) &&
522 Objects.equals(this.defaultMaxZoom, other.defaultMaxZoom) &&
523 Objects.equals(this.defaultMinZoom, other.defaultMinZoom) &&
524 Objects.equals(this.bounds, other.bounds) &&
525 Objects.equals(this.serverProjections, other.serverProjections) &&
526 Objects.equals(this.attributionText, other.attributionText) &&
527 Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
528 Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) &&
529 Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
530 Objects.equals(this.attributionImage, other.attributionImage) &&
531 Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
532 Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
533 Objects.equals(this.countryCode, other.countryCode) &&
534 Objects.equals(this.date, other.date) &&
535 Objects.equals(this.icon, other.icon) &&
536 Objects.equals(this.description, other.description) &&
537 Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
538 Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
539 Objects.equals(this.metadataHeaders, other.metadataHeaders) &&
540 Objects.equals(this.defaultLayers, other.defaultLayers);
541 // CHECKSTYLE.ON: BooleanExpressionComplexity
542 }
543
544 @Override
545 public boolean equals(Object o) {
546 if (this == o) return true;
547 if (o == null || getClass() != o.getClass()) return false;
548 ImageryInfo that = (ImageryInfo) o;
549 return imageryType == that.imageryType && Objects.equals(url, that.url);
550 }
551
552 @Override
553 public String toString() {
554 return "ImageryInfo{" +
555 "name='" + name + '\'' +
556 ", countryCode='" + countryCode + '\'' +
557 ", url='" + url + '\'' +
558 ", imageryType=" + imageryType +
559 '}';
560 }
561
562 @Override
563 public int compareTo(ImageryInfo in) {
564 int i = countryCode.compareTo(in.countryCode);
565 if (i == 0) {
566 i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
567 }
568 if (i == 0) {
569 i = url.compareTo(in.url);
570 }
571 if (i == 0) {
572 i = Double.compare(pixelPerDegree, in.pixelPerDegree);
573 }
574 return i;
575 }
576
577 /**
578 * Determines if URL is equal to given imagery info.
579 * @param in imagery info
580 * @return {@code true} if URL is equal to given imagery info
581 */
582 public boolean equalsBaseValues(ImageryInfo in) {
583 return url.equals(in.url);
584 }
585
586 /**
587 * Sets the pixel per degree value.
588 * @param ppd The ppd value
589 * @see #getPixelPerDegree()
590 */
591 public void setPixelPerDegree(double ppd) {
592 this.pixelPerDegree = ppd;
593 }
594
595 /**
596 * Sets the maximum zoom level.
597 * @param defaultMaxZoom The maximum zoom level
598 */
599 public void setDefaultMaxZoom(int defaultMaxZoom) {
600 this.defaultMaxZoom = defaultMaxZoom;
601 }
602
603 /**
604 * Sets the minimum zoom level.
605 * @param defaultMinZoom The minimum zoom level
606 */
607 public void setDefaultMinZoom(int defaultMinZoom) {
608 this.defaultMinZoom = defaultMinZoom;
609 }
610
611 /**
612 * Sets the imagery polygonial bounds.
613 * @param b The imagery bounds (non-rectangular)
614 */
615 public void setBounds(ImageryBounds b) {
616 this.bounds = b;
617 }
618
619 /**
620 * Returns the imagery polygonial bounds.
621 * @return The imagery bounds (non-rectangular)
622 */
623 public ImageryBounds getBounds() {
624 return bounds;
625 }
626
627 @Override
628 public boolean requiresAttribution() {
629 return attributionText != null || attributionLinkURL != null || attributionImage != null
630 || termsOfUseText != null || termsOfUseURL != null;
631 }
632
633 @Override
634 public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
635 return attributionText;
636 }
637
638 @Override
639 public String getAttributionLinkURL() {
640 return attributionLinkURL;
641 }
642
643 /**
644 * Return the permission reference URL.
645 * @return The url
646 * @see #setPermissionReferenceURL
647 * @since 11975
648 */
649 public String getPermissionReferenceURL() {
650 return permissionReferenceURL;
651 }
652
653 @Override
654 public Image getAttributionImage() {
655 ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
656 if (i != null) {
657 return i.getImage();
658 }
659 return null;
660 }
661
662 /**
663 * Return the raw attribution logo information (an URL to the image).
664 * @return The url text
665 * @since 12257
666 */
667 public String getAttributionImageRaw() {
668 return attributionImage;
669 }
670
671 @Override
672 public String getAttributionImageURL() {
673 return attributionImageURL;
674 }
675
676 @Override
677 public String getTermsOfUseText() {
678 return termsOfUseText;
679 }
680
681 @Override
682 public String getTermsOfUseURL() {
683 return termsOfUseURL;
684 }
685
686 /**
687 * Set the attribution text
688 * @param text The text
689 * @see #getAttributionText(int, ICoordinate, ICoordinate)
690 */
691 public void setAttributionText(String text) {
692 attributionText = text;
693 }
694
695 /**
696 * Set the attribution image
697 * @param url The url of the image.
698 * @see #getAttributionImageURL()
699 */
700 public void setAttributionImageURL(String url) {
701 attributionImageURL = url;
702 }
703
704 /**
705 * Set the image for the attribution
706 * @param res The image resource
707 * @see #getAttributionImage()
708 */
709 public void setAttributionImage(String res) {
710 attributionImage = res;
711 }
712
713 /**
714 * Sets the URL the attribution should link to.
715 * @param url The url.
716 * @see #getAttributionLinkURL()
717 */
718 public void setAttributionLinkURL(String url) {
719 attributionLinkURL = url;
720 }
721
722 /**
723 * Sets the permission reference URL.
724 * @param url The url.
725 * @see #getPermissionReferenceURL()
726 * @since 11975
727 */
728 public void setPermissionReferenceURL(String url) {
729 permissionReferenceURL = url;
730 }
731
732 /**
733 * Sets the text to display to the user as terms of use.
734 * @param text The text
735 * @see #getTermsOfUseText()
736 */
737 public void setTermsOfUseText(String text) {
738 termsOfUseText = text;
739 }
740
741 /**
742 * Sets a url that links to the terms of use text.
743 * @param text The url.
744 * @see #getTermsOfUseURL()
745 */
746 public void setTermsOfUseURL(String text) {
747 termsOfUseURL = text;
748 }
749
750 /**
751 * Sets the extended URL of this entry.
752 * @param url Entry extended URL containing in addition of service URL, its type and min/max zoom info
753 */
754 public void setExtendedUrl(String url) {
755 CheckParameterUtil.ensureParameterNotNull(url);
756
757 // Default imagery type is WMS
758 this.url = url;
759 this.imageryType = ImageryType.WMS;
760
761 defaultMaxZoom = 0;
762 defaultMinZoom = 0;
763 for (ImageryType type : ImageryType.values()) {
764 Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)\\])?:(.*)").matcher(url);
765 if (m.matches()) {
766 this.url = m.group(3);
767 this.imageryType = type;
768 if (m.group(2) != null) {
769 defaultMaxZoom = Integer.parseInt(m.group(2));
770 }
771 if (m.group(1) != null) {
772 defaultMinZoom = Integer.parseInt(m.group(1));
773 }
774 break;
775 }
776 }
777
778 if (serverProjections.isEmpty()) {
779 serverProjections = new ArrayList<>();
780 Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)\\}.*").matcher(url.toUpperCase(Locale.ENGLISH));
781 if (m.matches()) {
782 for (String p : m.group(1).split(",")) {
783 serverProjections.add(p);
784 }
785 }
786 }
787 }
788
789 /**
790 * Returns the entry name.
791 * @return The entry name
792 * @since 6968
793 */
794 public String getOriginalName() {
795 return this.origName != null ? this.origName : this.name;
796 }
797
798 /**
799 * Sets the entry name and handle translation.
800 * @param language The used language
801 * @param name The entry name
802 * @since 8091
803 */
804 public void setName(String language, String name) {
805 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
806 if (LanguageInfo.isBetterLanguage(langName, language)) {
807 this.name = isdefault ? tr(name) : name;
808 this.langName = language;
809 }
810 if (origName == null || isdefault) {
811 this.origName = name;
812 }
813 }
814
815 /**
816 * Store the id of this info to the preferences and clear it afterwards.
817 */
818 public void clearId() {
819 if (this.id != null) {
820 Collection<String> newAddedIds = new TreeSet<>(Main.pref.getCollection("imagery.layers.addedIds"));
821 newAddedIds.add(this.id);
822 Main.pref.putCollection("imagery.layers.addedIds", newAddedIds);
823 }
824 setId(null);
825 }
826
827 /**
828 * Determines if this entry is enabled by default.
829 * @return {@code true} if this entry is enabled by default, {@code false} otherwise
830 */
831 public boolean isDefaultEntry() {
832 return defaultEntry;
833 }
834
835 /**
836 * Sets the default state of this entry.
837 * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
838 */
839 public void setDefaultEntry(boolean defaultEntry) {
840 this.defaultEntry = defaultEntry;
841 }
842
843 /**
844 * Return the data part of HTTP cookies header in case the service requires cookies to work
845 * @return the cookie data part
846 */
847 @Override
848 public String getCookies() {
849 return this.cookies;
850 }
851
852 /**
853 * Gets the pixel per degree value
854 * @return The ppd value.
855 */
856 public double getPixelPerDegree() {
857 return this.pixelPerDegree;
858 }
859
860 /**
861 * Returns the maximum zoom level.
862 * @return The maximum zoom level
863 */
864 @Override
865 public int getMaxZoom() {
866 return this.defaultMaxZoom;
867 }
868
869 /**
870 * Returns the minimum zoom level.
871 * @return The minimum zoom level
872 */
873 @Override
874 public int getMinZoom() {
875 return this.defaultMinZoom;
876 }
877
878 /**
879 * Returns the description text when existing.
880 * @return The description
881 * @since 8065
882 */
883 public String getDescription() {
884 return this.description;
885 }
886
887 /**
888 * Sets the description text when existing.
889 * @param language The used language
890 * @param description the imagery description text
891 * @since 8091
892 */
893 public void setDescription(String language, String description) {
894 boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
895 if (LanguageInfo.isBetterLanguage(langDescription, language)) {
896 this.description = isdefault ? tr(description) : description;
897 this.langDescription = language;
898 }
899 }
900
901 /**
902 * Returns a tool tip text for display.
903 * @return The text
904 * @since 8065
905 */
906 public String getToolTipText() {
907 StringBuilder res = new StringBuilder(getName());
908 boolean html = false;
909 String dateStr = getDate();
910 if (dateStr != null && !dateStr.isEmpty()) {
911 res.append("<br>").append(tr("Date of imagery: {0}", dateStr));
912 html = true;
913 }
914 if (bestMarked) {
915 res.append("<br>").append(tr("This imagery is marked as best in this region in other editors."));
916 html = true;
917 }
918 String desc = getDescription();
919 if (desc != null && !desc.isEmpty()) {
920 res.append("<br>").append(Utils.escapeReservedCharactersHTML(desc));
921 html = true;
922 }
923 if (html) {
924 res.insert(0, "<html>").append("</html>");
925 }
926 return res.toString();
927 }
928
929 /**
930 * Returns the EULA acceptance URL, if any.
931 * @return The URL to an EULA text that has to be accepted before use, or {@code null}
932 */
933 public String getEulaAcceptanceRequired() {
934 return eulaAcceptanceRequired;
935 }
936
937 /**
938 * Sets the EULA acceptance URL.
939 * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
940 */
941 public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
942 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
943 }
944
945 /**
946 * Returns the ISO 3166-1-alpha-2 country code.
947 * @return The country code (2 letters)
948 */
949 public String getCountryCode() {
950 return countryCode;
951 }
952
953 /**
954 * Sets the ISO 3166-1-alpha-2 country code.
955 * @param countryCode The country code (2 letters)
956 */
957 public void setCountryCode(String countryCode) {
958 this.countryCode = countryCode;
959 }
960
961 /**
962 * Returns the date information.
963 * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where
964 * DD and MM as well as a second date are optional)
965 * @since 11570
966 */
967 public String getDate() {
968 return date;
969 }
970
971 /**
972 * Sets the date information.
973 * @param date The date information
974 * @since 11570
975 */
976 public void setDate(String date) {
977 this.date = date;
978 }
979
980 /**
981 * Returns the entry icon.
982 * @return The entry icon
983 */
984 public String getIcon() {
985 return icon;
986 }
987
988 /**
989 * Sets the entry icon.
990 * @param icon The entry icon
991 */
992 public void setIcon(String icon) {
993 this.icon = icon;
994 }
995
996 /**
997 * Get the projections supported by the server. Only relevant for
998 * WMS-type ImageryInfo at the moment.
999 * @return null, if no projections have been specified; the list
1000 * of supported projections otherwise.
1001 */
1002 public List<String> getServerProjections() {
1003 return Collections.unmodifiableList(serverProjections);
1004 }
1005
1006 /**
1007 * Sets the list of collections the server supports
1008 * @param serverProjections The list of supported projections
1009 */
1010 public void setServerProjections(Collection<String> serverProjections) {
1011 CheckParameterUtil.ensureParameterNotNull(serverProjections, "serverProjections");
1012 this.serverProjections = new ArrayList<>(serverProjections);
1013 }
1014
1015 /**
1016 * Returns the extended URL, containing in addition of service URL, its type and min/max zoom info.
1017 * @return The extended URL
1018 */
1019 public String getExtendedUrl() {
1020 return imageryType.getTypeString() + (defaultMaxZoom != 0
1021 ? ('['+(defaultMinZoom != 0 ? (Integer.toString(defaultMinZoom) + ',') : "")+defaultMaxZoom+']') : "") + ':' + url;
1022 }
1023
1024 /**
1025 * Gets a unique toolbar key to store this layer as toolbar item
1026 * @return The kay.
1027 */
1028 public String getToolbarName() {
1029 String res = name;
1030 if (pixelPerDegree != 0) {
1031 res += "#PPD="+pixelPerDegree;
1032 }
1033 return res;
1034 }
1035
1036 /**
1037 * Gets the name that should be displayed in the menu to add this imagery layer.
1038 * @return The text.
1039 */
1040 public String getMenuName() {
1041 String res = name;
1042 if (pixelPerDegree != 0) {
1043 res += " ("+pixelPerDegree+')';
1044 }
1045 return res;
1046 }
1047
1048 /**
1049 * Determines if this entry requires attribution.
1050 * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
1051 */
1052 public boolean hasAttribution() {
1053 return attributionText != null;
1054 }
1055
1056 /**
1057 * Copies attribution from another {@code ImageryInfo}.
1058 * @param i The other imagery info to get attribution from
1059 */
1060 public void copyAttribution(ImageryInfo i) {
1061 this.attributionImage = i.attributionImage;
1062 this.attributionImageURL = i.attributionImageURL;
1063 this.attributionText = i.attributionText;
1064 this.attributionLinkURL = i.attributionLinkURL;
1065 this.termsOfUseText = i.termsOfUseText;
1066 this.termsOfUseURL = i.termsOfUseURL;
1067 }
1068
1069 /**
1070 * Applies the attribution from this object to a tile source.
1071 * @param s The tile source
1072 */
1073 public void setAttribution(AbstractTileSource s) {
1074 if (attributionText != null) {
1075 if ("osm".equals(attributionText)) {
1076 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
1077 } else {
1078 s.setAttributionText(attributionText);
1079 }
1080 }
1081 if (attributionLinkURL != null) {
1082 if ("osm".equals(attributionLinkURL)) {
1083 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
1084 } else {
1085 s.setAttributionLinkURL(attributionLinkURL);
1086 }
1087 }
1088 if (attributionImage != null) {
1089 ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
1090 if (i != null) {
1091 s.setAttributionImage(i.getImage());
1092 }
1093 }
1094 if (attributionImageURL != null) {
1095 s.setAttributionImageURL(attributionImageURL);
1096 }
1097 if (termsOfUseText != null) {
1098 s.setTermsOfUseText(termsOfUseText);
1099 }
1100 if (termsOfUseURL != null) {
1101 if ("osm".equals(termsOfUseURL)) {
1102 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
1103 } else {
1104 s.setTermsOfUseURL(termsOfUseURL);
1105 }
1106 }
1107 }
1108
1109 /**
1110 * Returns the imagery type.
1111 * @return The imagery type
1112 */
1113 public ImageryType getImageryType() {
1114 return imageryType;
1115 }
1116
1117 /**
1118 * Sets the imagery type.
1119 * @param imageryType The imagery type
1120 */
1121 public void setImageryType(ImageryType imageryType) {
1122 this.imageryType = imageryType;
1123 }
1124
1125 /**
1126 * Returns true if this layer's URL is matched by one of the regular
1127 * expressions kept by the current OsmApi instance.
1128 * @return {@code true} is this entry is blacklisted, {@code false} otherwise
1129 */
1130 public boolean isBlacklisted() {
1131 Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
1132 return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
1133 }
1134
1135 /**
1136 * Sets the map of &lt;header name, header value&gt; that if any of this header
1137 * will be returned, then this tile will be treated as "no tile at this zoom level"
1138 *
1139 * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
1140 * @since 9613
1141 */
1142 public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
1143 if (noTileHeaders == null || noTileHeaders.isEmpty()) {
1144 this.noTileHeaders = null;
1145 } else {
1146 this.noTileHeaders = noTileHeaders.toMap();
1147 }
1148 }
1149
1150 @Override
1151 public Map<String, Set<String>> getNoTileHeaders() {
1152 return noTileHeaders;
1153 }
1154
1155 /**
1156 * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
1157 * will be returned, then this tile will be treated as "no tile at this zoom level"
1158 *
1159 * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
1160 * @since 9613
1161 */
1162 public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
1163 if (noTileChecksums == null || noTileChecksums.isEmpty()) {
1164 this.noTileChecksums = null;
1165 } else {
1166 this.noTileChecksums = noTileChecksums.toMap();
1167 }
1168 }
1169
1170 @Override
1171 public Map<String, Set<String>> getNoTileChecksums() {
1172 return noTileChecksums;
1173 }
1174
1175 /**
1176 * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
1177 * be moved to metadata
1178 *
1179 * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
1180 * @since 8418
1181 */
1182 public void setMetadataHeaders(Map<String, String> metadataHeaders) {
1183 if (metadataHeaders == null || metadataHeaders.isEmpty()) {
1184 this.metadataHeaders = null;
1185 } else {
1186 this.metadataHeaders = metadataHeaders;
1187 }
1188 }
1189
1190 /**
1191 * Gets the flag if the georeference is valid.
1192 * @return <code>true</code> if it is valid.
1193 */
1194 public boolean isGeoreferenceValid() {
1195 return isGeoreferenceValid;
1196 }
1197
1198 /**
1199 * Sets an indicator that the georeference is valid
1200 * @param isGeoreferenceValid <code>true</code> if it is marked as valid.
1201 */
1202 public void setGeoreferenceValid(boolean isGeoreferenceValid) {
1203 this.isGeoreferenceValid = isGeoreferenceValid;
1204 }
1205
1206 /**
1207 * Returns the status of "best" marked status in other editors.
1208 * @return <code>true</code> if it is marked as best.
1209 * @since 11575
1210 */
1211 public boolean isBestMarked() {
1212 return bestMarked;
1213 }
1214
1215 /**
1216 * Sets an indicator that in other editors it is marked as best imagery
1217 * @param bestMarked <code>true</code> if it is marked as best in other editors.
1218 * @since 11575
1219 */
1220 public void setBestMarked(boolean bestMarked) {
1221 this.bestMarked = bestMarked;
1222 }
1223
1224 /**
1225 * Adds a mirror entry. Mirror entries are completed with the data from the master entry
1226 * and only describe another method to access identical data.
1227 *
1228 * @param entry the mirror to be added
1229 * @since 9658
1230 */
1231 public void addMirror(ImageryInfo entry) {
1232 if (mirrors == null) {
1233 mirrors = new ArrayList<>();
1234 }
1235 mirrors.add(entry);
1236 }
1237
1238 /**
1239 * Returns the mirror entries. Entries are completed with master entry data.
1240 *
1241 * @return the list of mirrors
1242 * @since 9658
1243 */
1244 public List<ImageryInfo> getMirrors() {
1245 List<ImageryInfo> l = new ArrayList<>();
1246 if (mirrors != null) {
1247 int num = 1;
1248 for (ImageryInfo i : mirrors) {
1249 ImageryInfo n = new ImageryInfo(this);
1250 if (i.defaultMaxZoom != 0) {
1251 n.defaultMaxZoom = i.defaultMaxZoom;
1252 }
1253 if (i.defaultMinZoom != 0) {
1254 n.defaultMinZoom = i.defaultMinZoom;
1255 }
1256 n.setServerProjections(i.getServerProjections());
1257 n.url = i.url;
1258 n.imageryType = i.imageryType;
1259 if (i.getTileSize() != 0) {
1260 n.setTileSize(i.getTileSize());
1261 }
1262 if (n.id != null) {
1263 n.id = n.id + "_mirror"+num;
1264 }
1265 if (num > 1) {
1266 n.name = tr("{0} mirror server {1}", n.name, num);
1267 if (n.origName != null) {
1268 n.origName += " mirror server " + num;
1269 }
1270 } else {
1271 n.name = tr("{0} mirror server", n.name);
1272 if (n.origName != null) {
1273 n.origName += " mirror server";
1274 }
1275 }
1276 l.add(n);
1277 ++num;
1278 }
1279 }
1280 return l;
1281 }
1282
1283 /**
1284 * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)
1285 * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer
1286 * to work on
1287 * @return Collection of the layer names
1288 */
1289 public Collection<DefaultLayer> getDefaultLayers() {
1290 return defaultLayers;
1291 }
1292
1293 /**
1294 * Sets the default layers that user will work with
1295 * @param layers set the list of default layers
1296 */
1297 public void setDefaultLayers(Collection<DefaultLayer> layers) {
1298 if (ImageryType.WMTS.equals(this.imageryType)) {
1299 CheckParameterUtil.ensureThat(layers == null ||
1300 layers.isEmpty() ||
1301 layers.iterator().next() instanceof WMTSDefaultLayer, "Incorrect default layer");
1302 }
1303 this.defaultLayers = layers;
1304 }
1305}
Note: See TracBrowser for help on using the repository browser.