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

Last change on this file since 12445 was 12445, checked in by Don-vip, 21 months ago

update to error-prone 2.0.21, groovy 2.4.12

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