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

Last change on this file since 12841 was 12841, checked in by bastiK, 3 months ago

see #15229 - fix deprecations caused by [12840]

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