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

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

sonar - squid:S3052 - Fields should not be initialized to default values

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