Ticket #19026: 19026.patch

File 19026.patch, 128.3 KB (added by taylor.smock, 5 years ago)

Initial WIP patch (very broken, its a work in progress :) )

  • src/org/openstreetmap/josm/data/imagery/ImageryInfo.java

     
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
    55
    6 import java.awt.Image;
    76import java.io.StringReader;
    8 import java.util.ArrayList;
    97import java.util.Arrays;
    108import java.util.Collection;
    119import java.util.Collections;
    1210import java.util.EnumMap;
    13 import java.util.HashMap;
    1411import java.util.List;
    1512import java.util.Locale;
    1613import java.util.Map;
    1714import java.util.Objects;
    18 import java.util.Optional;
    19 import java.util.Set;
    20 import java.util.TreeSet;
    2115import java.util.concurrent.TimeUnit;
    2216import java.util.regex.Matcher;
    2317import java.util.regex.Pattern;
     
    2923import javax.json.stream.JsonCollectors;
    3024import javax.swing.ImageIcon;
    3125
    32 import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
    33 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
    34 import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
    35 import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
    36 import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
    37 import org.openstreetmap.josm.data.Bounds;
    38 import org.openstreetmap.josm.data.StructUtils;
    3926import org.openstreetmap.josm.data.StructUtils.StructEntry;
    40 import org.openstreetmap.josm.io.Capabilities;
    41 import org.openstreetmap.josm.io.OsmApi;
    42 import org.openstreetmap.josm.spi.preferences.Config;
    43 import org.openstreetmap.josm.spi.preferences.IPreferences;
     27import org.openstreetmap.josm.data.sources.ISourceCategory;
     28import org.openstreetmap.josm.data.sources.ISourceType;
     29import org.openstreetmap.josm.data.sources.SourceBounds;
     30import org.openstreetmap.josm.data.sources.SourceInfo;
     31import org.openstreetmap.josm.data.sources.SourcePreferenceEntry;
    4432import org.openstreetmap.josm.tools.CheckParameterUtil;
    4533import org.openstreetmap.josm.tools.ImageProvider;
    4634import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
    47 import org.openstreetmap.josm.tools.LanguageInfo;
    4835import org.openstreetmap.josm.tools.Logging;
    4936import org.openstreetmap.josm.tools.MultiMap;
    5037import org.openstreetmap.josm.tools.Utils;
     
    5441 *
    5542 * @author Frederik Ramm
    5643 */
    57 public class ImageryInfo extends TileSourceInfo implements Comparable<ImageryInfo>, Attributed {
     44public class ImageryInfo extends SourceInfo<ImageryInfo.ImageryCategory, ImageryInfo.ImageryType, ImageryInfo.ImageryBounds, ImageryInfo.ImageryPreferenceEntry> {
    5845
    5946    /**
    6047     * Type of imagery entry.
    6148     */
    62     public enum ImageryType {
     49    public enum ImageryType implements ISourceType<ImageryType> {
    6350        /** A WMS (Web Map Service) entry. **/
    6451        WMS("wms"),
    6552        /** A TMS (Tile Map Service) entry. **/
     
    8471         * @return the unique string identifying this type
    8572         * @since 6690
    8673         */
     74        @Override
    8775        public final String getTypeString() {
    8876            return typeString;
    8977        }
     
    9381         * @param s The type string
    9482         * @return the imagery type matching the given type string
    9583         */
    96         public static ImageryType fromString(String s) {
     84        public static ImageryType getFromString(String s) {
    9785            for (ImageryType type : ImageryType.values()) {
    9886                if (type.getTypeString().equals(s)) {
    9987                    return type;
     
    10189            }
    10290            return null;
    10391        }
     92
     93        @Override
     94        public ImageryType fromString(String s) {
     95            return getFromString(s);
     96        }
     97
     98        @Override
     99        public ImageryType getDefault() {
     100            return WMS;
     101        }
    104102    }
    105103
    106104    /**
     
    107105     * Category of imagery entry.
    108106     * @since 13792
    109107     */
    110     public enum ImageryCategory {
     108    public enum ImageryCategory implements ISourceCategory<ImageryCategory> {
    111109        /** A aerial or satellite photo. **/
    112110        PHOTO(/* ICON(data/imagery/) */ "photo", tr("Aerial or satellite photo")),
    113111        /** A map of digital terrain model, digital surface model or contour lines. **/
     
    139137         * Returns the unique string identifying this category.
    140138         * @return the unique string identifying this category
    141139         */
     140        @Override
    142141        public final String getCategoryString() {
    143142            return category;
    144143        }
     
    147146         * Returns the description of this category.
    148147         * @return the description of this category
    149148         */
     149        @Override
    150150        public final String getDescription() {
    151151            return description;
    152152        }
     
    157157         * @return the category icon at the given size
    158158         * @since 15049
    159159         */
     160        @Override
    160161        public final ImageIcon getIcon(ImageSizes size) {
    161162            return iconCache
    162163                    .computeIfAbsent(size, x -> Collections.synchronizedMap(new EnumMap<>(ImageryCategory.class)))
     
    168169         * @param s The category string
    169170         * @return the imagery category matching the given category string
    170171         */
    171         public static ImageryCategory fromString(String s) {
     172        public static ImageryCategory getFromString(String s) {
    172173            for (ImageryCategory category : ImageryCategory.values()) {
    173174                if (category.getCategoryString().equals(s)) {
    174175                    return category;
     
    176177            }
    177178            return null;
    178179        }
     180
     181        @Override
     182        public ImageryCategory getDefault() {
     183            return OTHER;
     184        }
     185
     186        @Override
     187        public ImageryCategory fromString(String s) {
     188            return getFromString(s);
     189        }
    179190    }
    180191
    181192    /**
     
    182193     * Multi-polygon bounds for imagery backgrounds.
    183194     * Used to display imagery coverage in preferences and to determine relevant imagery entries based on edit location.
    184195     */
    185     public static class ImageryBounds extends Bounds {
     196    public static class ImageryBounds extends SourceBounds {
    186197
    187198        /**
    188199         * Constructs a new {@code ImageryBounds} from string.
     
    192203        public ImageryBounds(String asString, String separator) {
    193204            super(asString, separator);
    194205        }
    195 
    196         private List<Shape> shapes = new ArrayList<>();
    197 
    198         /**
    199          * Adds a new shape to this bounds.
    200          * @param shape The shape to add
    201          */
    202         public final void addShape(Shape shape) {
    203             this.shapes.add(shape);
    204         }
    205 
    206         /**
    207          * Sets the list of shapes defining this bounds.
    208          * @param shapes The list of shapes defining this bounds.
    209          */
    210         public final void setShapes(List<Shape> shapes) {
    211             this.shapes = shapes;
    212         }
    213 
    214         /**
    215          * Returns the list of shapes defining this bounds.
    216          * @return The list of shapes defining this bounds
    217          */
    218         public final List<Shape> getShapes() {
    219             return shapes;
    220         }
    221 
    222         @Override
    223         public int hashCode() {
    224             return Objects.hash(super.hashCode(), shapes);
    225         }
    226 
    227         @Override
    228         public boolean equals(Object o) {
    229             if (this == o) return true;
    230             if (o == null || getClass() != o.getClass()) return false;
    231             if (!super.equals(o)) return false;
    232             ImageryBounds that = (ImageryBounds) o;
    233             return Objects.equals(shapes, that.shapes);
    234         }
    235206    }
    236207
    237     /** original name of the imagery entry in case of translation call, for multiple languages English when possible */
    238     private String origName;
    239     /** (original) language of the translated name entry */
    240     private String langName;
    241     /** whether this is a entry activated by default or not */
    242     private boolean defaultEntry;
    243     /** Whether this service requires a explicit EULA acceptance before it can be activated */
    244     private String eulaAcceptanceRequired;
    245     /** type of the imagery servics - WMS, TMS, ... */
    246     private ImageryType imageryType = ImageryType.WMS;
    247208    private double pixelPerDegree;
    248209    /** maximum zoom level for TMS imagery */
    249210    private int defaultMaxZoom;
    250211    /** minimum zoom level for TMS imagery */
    251212    private int defaultMinZoom;
    252     /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */
    253     private ImageryBounds bounds;
    254213    /** projections supported by WMS servers */
    255214    private List<String> serverProjections = Collections.emptyList();
    256     /** description of the imagery entry, should contain notes what type of data it is */
    257     private String description;
    258     /** language of the description entry */
    259     private String langDescription;
    260     /** Text of a text attribution displayed when using the imagery */
    261     private String attributionText;
    262     /** Link to the privacy policy of the operator */
    263     private String privacyPolicyURL;
    264     /** Link to a reference stating the permission for OSM usage */
    265     private String permissionReferenceURL;
    266     /** Link behind the text attribution displayed when using the imagery */
    267     private String attributionLinkURL;
    268     /** Image of a graphical attribution displayed when using the imagery */
    269     private String attributionImage;
    270     /** Link behind the graphical attribution displayed when using the imagery */
    271     private String attributionImageURL;
    272     /** Text with usage terms displayed when using the imagery */
    273     private String termsOfUseText;
    274     /** Link behind the text with usage terms displayed when using the imagery */
    275     private String termsOfUseURL;
    276     /** country code of the imagery (for country specific imagery) */
    277     private String countryCode = "";
    278215    /**
    279       * creation date of the imagery (in the form YYYY-MM-DD;YYYY-MM-DD, where
    280       * DD and MM as well as a second date are optional).
    281       *
    282       * Also used as time filter for WMS time={time} parameter (such as Sentinel-2)
    283       * @since 11570
    284       */
    285     private String date;
    286     /**
    287216      * marked as best in other editors
    288217      * @since 11575
    289218      */
     
    294223      */
    295224    private boolean overlay;
    296225    /**
    297       * list of old IDs, only for loading, not handled anywhere else
    298       * @since 13536
    299       */
    300     private Collection<String> oldIds;
    301     /** mirrors of different type for this entry */
    302     private List<ImageryInfo> mirrors;
    303     /** icon used in menu */
    304     private String icon;
     226     * Auxiliary class to save an {@link ImageryInfo} object in the preferences.
     227     */
    305228    /** is the geo reference correct - don't offer offset handling */
    306229    private boolean isGeoreferenceValid;
    307     /** which layers should be activated by default on layer addition. **/
    308     private List<DefaultLayer> defaultLayers = Collections.emptyList();
    309     /** HTTP headers **/
    310     private Map<String, String> customHttpHeaders = Collections.emptyMap();
    311230    /** Should this map be transparent **/
    312231    private boolean transparent = true;
    313232    private int minimumTileExpire = (int) TimeUnit.MILLISECONDS.toSeconds(TMSCachedTileLoaderJob.MINIMUM_EXPIRES.get());
    314     /** category of the imagery */
    315     private ImageryCategory category;
    316     /** category of the imagery (input string, not saved, copied or used otherwise except for error checks) */
    317     private String categoryOriginalString;
    318     /** when adding a field, also adapt the:
    319      * {@link #ImageryPreferenceEntry ImageryPreferenceEntry object}
    320      * {@link #ImageryPreferenceEntry#ImageryPreferenceEntry(ImageryInfo) ImageryPreferenceEntry constructor}
    321      * {@link #ImageryInfo(ImageryPreferenceEntry) ImageryInfo constructor}
    322      * {@link #ImageryInfo(ImageryInfo) ImageryInfo constructor}
    323      * {@link #equalsPref(ImageryPreferenceEntry) equalsPref method}
    324      **/
    325233
    326     /**
    327      * Auxiliary class to save an {@link ImageryInfo} object in the preferences.
    328      */
    329     public static class ImageryPreferenceEntry {
     234    public static class ImageryPreferenceEntry extends SourcePreferenceEntry<ImageryInfo> {
    330235        @StructEntry String name;
    331236        @StructEntry String d;
    332237        @StructEntry String id;
     
    379284        public ImageryPreferenceEntry(ImageryInfo i) {
    380285            name = i.name;
    381286            id = i.id;
    382             type = i.imageryType.getTypeString();
     287            type = i.sourceType.getTypeString();
    383288            url = i.url;
    384289            pixel_per_eastnorth = i.pixelPerDegree;
    385290            eula = i.eulaAcceptanceRequired;
     
    500405    public ImageryInfo(String name, String url, String type, String eulaAcceptanceRequired, String cookies) {
    501406        this(name);
    502407        setExtendedUrl(url);
    503         ImageryType t = ImageryType.fromString(type);
     408        ImageryType t = ImageryType.getFromString(type);
    504409        this.cookies = cookies;
    505410        this.eulaAcceptanceRequired = eulaAcceptanceRequired;
    506411        if (t != null) {
    507             this.imageryType = t;
     412            this.sourceType = t;
    508413        } else if (type != null && !type.isEmpty()) {
    509414            throw new IllegalArgumentException("unknown type: "+type);
    510415        }
     
    536441        description = e.description;
    537442        cookies = e.cookies;
    538443        eulaAcceptanceRequired = e.eula;
    539         imageryType = ImageryType.fromString(e.type);
    540         if (imageryType == null) throw new IllegalArgumentException("unknown type");
     444        sourceType = ImageryType.getFromString(e.type);
     445        if (sourceType == null) throw new IllegalArgumentException("unknown type");
    541446        pixelPerDegree = e.pixel_per_eastnorth;
    542447        defaultMaxZoom = e.max_zoom;
    543448        defaultMinZoom = e.min_zoom;
     
    584489                defaultLayers = jsonReader.
    585490                        readArray().
    586491                        stream().
    587                         map(x -> DefaultLayer.fromJson((JsonObject) x, imageryType)).
     492                        map(x -> DefaultLayer.fromJson((JsonObject) x, sourceType)).
    588493                        collect(Collectors.toList());
    589494            }
    590495        }
     
    591496        setCustomHttpHeaders(e.customHttpHeaders);
    592497        transparent = e.transparent;
    593498        minimumTileExpire = e.minimumTileExpire;
    594         category = ImageryCategory.fromString(e.category);
     499        category = ImageryCategory.getFromString(e.category);
    595500    }
    596501
    597502    /**
     
    613518        this.langName = i.langName;
    614519        this.defaultEntry = i.defaultEntry;
    615520        this.eulaAcceptanceRequired = null;
    616         this.imageryType = i.imageryType;
     521        this.sourceType = i.sourceType;
    617522        this.pixelPerDegree = i.pixelPerDegree;
    618523        this.defaultMaxZoom = i.defaultMaxZoom;
    619524        this.defaultMinZoom = i.defaultMinZoom;
     
    644549        this.category = i.category;
    645550    }
    646551
    647     @Override
    648     public int hashCode() {
    649         return Objects.hash(url, imageryType);
    650     }
    651 
    652552    /**
    653553     * Check if this object equals another ImageryInfo with respect to the properties
    654554     * that get written to the preference file.
     
    658558     * @param other the ImageryInfo object to compare to
    659559     * @return true if they are equal
    660560     */
    661     public boolean equalsPref(ImageryInfo other) {
    662         if (other == null) {
     561    @Override
     562    public boolean equalsPref(SourceInfo<ImageryInfo.ImageryCategory,ImageryInfo.ImageryType,ImageryInfo.ImageryBounds,ImageryInfo.ImageryPreferenceEntry> other) {
     563        if (!(other instanceof ImageryInfo)) {
    663564            return false;
    664565        }
     566        ImageryInfo realOther = (ImageryInfo) other;
    665567
    666568        // CHECKSTYLE.OFF: BooleanExpressionComplexity
    667         return
    668                 Objects.equals(this.name, other.name) &&
    669                 Objects.equals(this.id, other.id) &&
    670                 Objects.equals(this.url, other.url) &&
    671                 Objects.equals(this.modTileFeatures, other.modTileFeatures) &&
    672                 Objects.equals(this.bestMarked, other.bestMarked) &&
    673                 Objects.equals(this.overlay, other.overlay) &&
    674                 Objects.equals(this.isGeoreferenceValid, other.isGeoreferenceValid) &&
    675                 Objects.equals(this.cookies, other.cookies) &&
    676                 Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
    677                 Objects.equals(this.imageryType, other.imageryType) &&
    678                 Objects.equals(this.defaultMaxZoom, other.defaultMaxZoom) &&
    679                 Objects.equals(this.defaultMinZoom, other.defaultMinZoom) &&
    680                 Objects.equals(this.bounds, other.bounds) &&
    681                 Objects.equals(this.serverProjections, other.serverProjections) &&
    682                 Objects.equals(this.attributionText, other.attributionText) &&
    683                 Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
    684                 Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) &&
    685                 Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
    686                 Objects.equals(this.attributionImage, other.attributionImage) &&
    687                 Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
    688                 Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
    689                 Objects.equals(this.countryCode, other.countryCode) &&
    690                 Objects.equals(this.date, other.date) &&
    691                 Objects.equals(this.icon, other.icon) &&
    692                 Objects.equals(this.description, other.description) &&
    693                 Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
    694                 Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
    695                 Objects.equals(this.metadataHeaders, other.metadataHeaders) &&
    696                 Objects.equals(this.defaultLayers, other.defaultLayers) &&
    697                 Objects.equals(this.customHttpHeaders, other.customHttpHeaders) &&
    698                 Objects.equals(this.transparent, other.transparent) &&
    699                 Objects.equals(this.minimumTileExpire, other.minimumTileExpire) &&
    700                 Objects.equals(this.category, other.category);
     569        return super.equalsPref(realOther) &&
     570                Objects.equals(this.bestMarked, realOther.bestMarked) &&
     571                Objects.equals(this.overlay, realOther.overlay) &&
     572                Objects.equals(this.isGeoreferenceValid, realOther.isGeoreferenceValid) &&
     573                Objects.equals(this.defaultMaxZoom, realOther.defaultMaxZoom) &&
     574                Objects.equals(this.defaultMinZoom, realOther.defaultMinZoom) &&
     575                Objects.equals(this.serverProjections, realOther.serverProjections) &&
     576                Objects.equals(this.transparent, realOther.transparent) &&
     577                Objects.equals(this.minimumTileExpire, realOther.minimumTileExpire);
    701578        // CHECKSTYLE.ON: BooleanExpressionComplexity
    702579    }
    703580
    704581    @Override
    705     public boolean equals(Object o) {
    706         if (this == o) return true;
    707         if (o == null || getClass() != o.getClass()) return false;
    708         ImageryInfo that = (ImageryInfo) o;
    709         return imageryType == that.imageryType && Objects.equals(url, that.url);
    710     }
    711 
    712     private static final Map<String, String> localizedCountriesCache = new HashMap<>();
    713     static {
    714         localizedCountriesCache.put("", tr("Worldwide"));
    715     }
    716 
    717     /**
    718      * Returns a localized name for the given country code, or "Worldwide" if empty.
    719      * This function falls back on the English name, and uses the ISO code as a last-resortvalue.
    720      *
    721      * @param countryCode An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code
    722      * @return The name of the country appropriate to the current locale.
    723      * @see Locale#getDisplayCountry
    724      * @since 15158
    725      */
    726     public static String getLocalizedCountry(String countryCode) {
    727         return localizedCountriesCache.computeIfAbsent(countryCode, code -> new Locale("en", code).getDisplayCountry());
    728     }
    729 
    730     @Override
    731     public String toString() {
    732         // Used in imagery preferences filtering, so must be efficient
    733         return new StringBuilder(name)
    734                 .append('[').append(countryCode)
    735                 // appending the localized country in toString() allows us to filter imagery preferences table with it!
    736                 .append("] ('").append(getLocalizedCountry(countryCode)).append(')')
    737                 .append(" - ").append(url)
    738                 .append(" - ").append(imageryType)
    739                 .toString();
    740     }
    741 
    742     @Override
    743     public int compareTo(ImageryInfo in) {
    744         int i = countryCode.compareTo(in.countryCode);
    745         if (i == 0) {
    746             i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
     582    public int compareTo(SourceInfo<ImageryInfo.ImageryCategory,ImageryInfo.ImageryType,ImageryInfo.ImageryBounds,ImageryInfo.ImageryPreferenceEntry> other) {
     583        int i = super.compareTo(other);
     584        if (other instanceof ImageryInfo) {
     585            ImageryInfo in = (ImageryInfo) other;
     586            if (i == 0) {
     587                i = Double.compare(pixelPerDegree, in.pixelPerDegree);
     588            }
    747589        }
    748         if (i == 0) {
    749             i = url.compareTo(in.url);
    750         }
    751         if (i == 0) {
    752             i = Double.compare(pixelPerDegree, in.pixelPerDegree);
    753         }
    754590        return i;
    755591    }
    756592
    757593    /**
    758      * Determines if URL is equal to given imagery info.
    759      * @param in imagery info
    760      * @return {@code true} if URL is equal to given imagery info
    761      */
    762     public boolean equalsBaseValues(ImageryInfo in) {
    763         return url.equals(in.url);
    764     }
    765 
    766     /**
    767594     * Sets the pixel per degree value.
    768595     * @param ppd The ppd value
    769596     * @see #getPixelPerDegree()
     
    789616    }
    790617
    791618    /**
    792      * Sets the imagery polygonial bounds.
    793      * @param b The imagery bounds (non-rectangular)
    794      */
    795     public void setBounds(ImageryBounds b) {
    796         this.bounds = b;
    797     }
    798 
    799     /**
    800      * Returns the imagery polygonial bounds.
    801      * @return The imagery bounds (non-rectangular)
    802      */
    803     public ImageryBounds getBounds() {
    804         return bounds;
    805     }
    806 
    807     @Override
    808     public boolean requiresAttribution() {
    809         return attributionText != null || attributionLinkURL != null || attributionImage != null
    810                 || termsOfUseText != null || termsOfUseURL != null;
    811     }
    812 
    813     @Override
    814     public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
    815         return attributionText;
    816     }
    817 
    818     @Override
    819     public String getAttributionLinkURL() {
    820         return attributionLinkURL;
    821     }
    822 
    823     /**
    824      * Return the permission reference URL.
    825      * @return The url
    826      * @see #setPermissionReferenceURL
    827      * @since 11975
    828      */
    829     public String getPermissionReferenceURL() {
    830         return permissionReferenceURL;
    831     }
    832 
    833     /**
    834      * Return the privacy policy URL.
    835      * @return The url
    836      * @see #setPrivacyPolicyURL
    837      * @since 16127
    838      */
    839     public String getPrivacyPolicyURL() {
    840         return privacyPolicyURL;
    841     }
    842 
    843     @Override
    844     public Image getAttributionImage() {
    845         ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
    846         if (i != null) {
    847             return i.getImage();
    848         }
    849         return null;
    850     }
    851 
    852     /**
    853      * Return the raw attribution logo information (an URL to the image).
    854      * @return The url text
    855      * @since 12257
    856      */
    857     public String getAttributionImageRaw() {
    858         return attributionImage;
    859     }
    860 
    861     @Override
    862     public String getAttributionImageURL() {
    863         return attributionImageURL;
    864     }
    865 
    866     @Override
    867     public String getTermsOfUseText() {
    868         return termsOfUseText;
    869     }
    870 
    871     @Override
    872     public String getTermsOfUseURL() {
    873         return termsOfUseURL;
    874     }
    875 
    876     /**
    877      * Set the attribution text
    878      * @param text The text
    879      * @see #getAttributionText(int, ICoordinate, ICoordinate)
    880      */
    881     public void setAttributionText(String text) {
    882         attributionText = intern(text);
    883     }
    884 
    885     /**
    886      * Set the attribution image
    887      * @param url The url of the image.
    888      * @see #getAttributionImageURL()
    889      */
    890     public void setAttributionImageURL(String url) {
    891         attributionImageURL = url;
    892     }
    893 
    894     /**
    895      * Set the image for the attribution
    896      * @param res The image resource
    897      * @see #getAttributionImage()
    898      */
    899     public void setAttributionImage(String res) {
    900         attributionImage = res;
    901     }
    902 
    903     /**
    904      * Sets the URL the attribution should link to.
    905      * @param url The url.
    906      * @see #getAttributionLinkURL()
    907      */
    908     public void setAttributionLinkURL(String url) {
    909         attributionLinkURL = url;
    910     }
    911 
    912     /**
    913      * Sets the permission reference URL.
    914      * @param url The url.
    915      * @see #getPermissionReferenceURL()
    916      * @since 11975
    917      */
    918     public void setPermissionReferenceURL(String url) {
    919         permissionReferenceURL = url;
    920     }
    921 
    922     /**
    923      * Sets the privacy policy URL.
    924      * @param url The url.
    925      * @see #getPrivacyPolicyURL()
    926      * @since 16127
    927      */
    928     public void setPrivacyPolicyURL(String url) {
    929         privacyPolicyURL = url;
    930     }
    931 
    932     /**
    933      * Sets the text to display to the user as terms of use.
    934      * @param text The text
    935      * @see #getTermsOfUseText()
    936      */
    937     public void setTermsOfUseText(String text) {
    938         termsOfUseText = text;
    939     }
    940 
    941     /**
    942      * Sets a url that links to the terms of use text.
    943      * @param text The url.
    944      * @see #getTermsOfUseURL()
    945      */
    946     public void setTermsOfUseURL(String text) {
    947         termsOfUseURL = text;
    948     }
    949 
    950     /**
    951619     * Sets the extended URL of this entry.
    952620     * @param url Entry extended URL containing in addition of service URL, its type and min/max zoom info
    953621     */
     
    956624
    957625        // Default imagery type is WMS
    958626        this.url = url;
    959         this.imageryType = ImageryType.WMS;
     627        this.sourceType = ImageryType.WMS;
    960628
    961629        defaultMaxZoom = 0;
    962630        defaultMinZoom = 0;
     
    964632            Matcher m = Pattern.compile(type.getTypeString()+"(?:\\[(?:(\\d+)[,-])?(\\d+)\\])?:(.*)").matcher(url);
    965633            if (m.matches()) {
    966634                this.url = m.group(3);
    967                 this.imageryType = type;
     635                this.sourceType = type;
    968636                if (m.group(2) != null) {
    969637                    defaultMaxZoom = Integer.parseInt(m.group(2));
    970638                }
     
    982650            }
    983651        }
    984652    }
    985 
    986653    /**
    987      * Returns the entry name.
    988      * @return The entry name
    989      * @since 6968
    990      */
    991     public String getOriginalName() {
    992         return this.origName != null ? this.origName : this.name;
    993     }
    994 
    995     /**
    996      * Sets the entry name and handle translation.
    997      * @param language The used language
    998      * @param name The entry name
    999      * @since 8091
    1000      */
    1001     public void setName(String language, String name) {
    1002         boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
    1003         if (LanguageInfo.isBetterLanguage(langName, language)) {
    1004             this.name = isdefault ? tr(name) : name;
    1005             this.langName = language;
    1006         }
    1007         if (origName == null || isdefault) {
    1008             this.origName = name;
    1009         }
    1010     }
    1011 
    1012     /**
    1013      * Store the id of this info to the preferences and clear it afterwards.
    1014      */
    1015     public void clearId() {
    1016         if (this.id != null) {
    1017             Collection<String> newAddedIds = new TreeSet<>(Config.getPref().getList("imagery.layers.addedIds"));
    1018             newAddedIds.add(this.id);
    1019             Config.getPref().putList("imagery.layers.addedIds", new ArrayList<>(newAddedIds));
    1020         }
    1021         setId(null);
    1022     }
    1023 
    1024     /**
    1025      * Determines if this entry is enabled by default.
    1026      * @return {@code true} if this entry is enabled by default, {@code false} otherwise
    1027      */
    1028     public boolean isDefaultEntry() {
    1029         return defaultEntry;
    1030     }
    1031 
    1032     /**
    1033      * Sets the default state of this entry.
    1034      * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
    1035      */
    1036     public void setDefaultEntry(boolean defaultEntry) {
    1037         this.defaultEntry = defaultEntry;
    1038     }
    1039 
    1040     /**
    1041654     * Gets the pixel per degree value
    1042655     * @return The ppd value.
    1043656     */
     
    1064677    }
    1065678
    1066679    /**
    1067      * Returns the description text when existing.
    1068      * @return The description
    1069      * @since 8065
    1070      */
    1071     public String getDescription() {
    1072         return this.description;
    1073     }
    1074 
    1075     /**
    1076      * Sets the description text when existing.
    1077      * @param language The used language
    1078      * @param description the imagery description text
    1079      * @since 8091
    1080      */
    1081     public void setDescription(String language, String description) {
    1082         boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
    1083         if (LanguageInfo.isBetterLanguage(langDescription, language)) {
    1084             this.description = isdefault ? tr(description) : description;
    1085             this.langDescription = intern(language);
    1086         }
    1087     }
    1088 
    1089     /**
    1090      * Return the sorted list of activated Imagery IDs.
    1091      * @return sorted list of activated Imagery IDs
    1092      * @since 13536
    1093      */
    1094     public static Collection<String> getActiveIds() {
    1095         ArrayList<String> ids = new ArrayList<>();
    1096         IPreferences pref = Config.getPref();
    1097         if (pref != null) {
    1098             List<ImageryPreferenceEntry> entries = StructUtils.getListOfStructs(
    1099                 pref, "imagery.entries", null, ImageryPreferenceEntry.class);
    1100             if (entries != null) {
    1101                 for (ImageryPreferenceEntry prefEntry : entries) {
    1102                     if (prefEntry.id != null && !prefEntry.id.isEmpty())
    1103                         ids.add(prefEntry.id);
    1104                 }
    1105                 Collections.sort(ids);
    1106             }
    1107         }
    1108         return ids;
    1109     }
    1110 
    1111     /**
    1112680     * Returns a tool tip text for display.
    1113681     * @return The text
    1114682     * @since 8065
    1115683     */
     684    @Override
    1116685    public String getToolTipText() {
    1117686        StringBuilder res = new StringBuilder(getName());
    1118687        boolean html = false;
     
    1143712        }
    1144713        return res.toString();
    1145714    }
    1146 
    1147715    /**
    1148      * Returns the EULA acceptance URL, if any.
    1149      * @return The URL to an EULA text that has to be accepted before use, or {@code null}
    1150      */
    1151     public String getEulaAcceptanceRequired() {
    1152         return eulaAcceptanceRequired;
    1153     }
    1154 
    1155     /**
    1156      * Sets the EULA acceptance URL.
    1157      * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
    1158      */
    1159     public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
    1160         this.eulaAcceptanceRequired = eulaAcceptanceRequired;
    1161     }
    1162 
    1163     /**
    1164      * Returns the ISO 3166-1-alpha-2 country code.
    1165      * @return The country code (2 letters)
    1166      */
    1167     public String getCountryCode() {
    1168         return countryCode;
    1169     }
    1170 
    1171     /**
    1172      * Sets the ISO 3166-1-alpha-2 country code.
    1173      * @param countryCode The country code (2 letters)
    1174      */
    1175     public void setCountryCode(String countryCode) {
    1176         this.countryCode = intern(countryCode);
    1177     }
    1178 
    1179     /**
    1180      * Returns the date information.
    1181      * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where
    1182      * DD and MM as well as a second date are optional)
    1183      * @since 11570
    1184      */
    1185     public String getDate() {
    1186         return date;
    1187     }
    1188 
    1189     /**
    1190      * Sets the date information.
    1191      * @param date The date information
    1192      * @since 11570
    1193      */
    1194     public void setDate(String date) {
    1195         this.date = date;
    1196     }
    1197 
    1198     /**
    1199      * Returns the entry icon.
    1200      * @return The entry icon
    1201      */
    1202     public String getIcon() {
    1203         return icon;
    1204     }
    1205 
    1206     /**
    1207      * Sets the entry icon.
    1208      * @param icon The entry icon
    1209      */
    1210     public void setIcon(String icon) {
    1211         this.icon = intern(icon);
    1212     }
    1213 
    1214     /**
    1215716     * Get the projections supported by the server. Only relevant for
    1216717     * WMS-type ImageryInfo at the moment.
    1217718     * @return null, if no projections have been specified; the list
     
    1237738     * @return The extended URL
    1238739     */
    1239740    public String getExtendedUrl() {
    1240         return imageryType.getTypeString() + (defaultMaxZoom != 0
     741        return sourceType.getTypeString() + (defaultMaxZoom != 0
    1241742            ? ('['+(defaultMinZoom != 0 ? (Integer.toString(defaultMinZoom) + ',') : "")+defaultMaxZoom+']') : "") + ':' + url;
    1242743    }
    1243744
     
    1265766        return res;
    1266767    }
    1267768
    1268     /**
    1269      * Determines if this entry requires attribution.
    1270      * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
    1271      */
    1272     public boolean hasAttribution() {
    1273         return attributionText != null;
    1274     }
    1275769
    1276770    /**
    1277      * Copies attribution from another {@code ImageryInfo}.
    1278      * @param i The other imagery info to get attribution from
    1279      */
    1280     public void copyAttribution(ImageryInfo i) {
    1281         this.attributionImage = i.attributionImage;
    1282         this.attributionImageURL = i.attributionImageURL;
    1283         this.attributionText = i.attributionText;
    1284         this.attributionLinkURL = i.attributionLinkURL;
    1285         this.termsOfUseText = i.termsOfUseText;
    1286         this.termsOfUseURL = i.termsOfUseURL;
    1287     }
    1288 
    1289     /**
    1290      * Applies the attribution from this object to a tile source.
    1291      * @param s The tile source
    1292      */
    1293     public void setAttribution(AbstractTileSource s) {
    1294         if (attributionText != null) {
    1295             if ("osm".equals(attributionText)) {
    1296                 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
    1297             } else {
    1298                 s.setAttributionText(attributionText);
    1299             }
    1300         }
    1301         if (attributionLinkURL != null) {
    1302             if ("osm".equals(attributionLinkURL)) {
    1303                 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
    1304             } else {
    1305                 s.setAttributionLinkURL(attributionLinkURL);
    1306             }
    1307         }
    1308         if (attributionImage != null) {
    1309             ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
    1310             if (i != null) {
    1311                 s.setAttributionImage(i.getImage());
    1312             }
    1313         }
    1314         if (attributionImageURL != null) {
    1315             s.setAttributionImageURL(attributionImageURL);
    1316         }
    1317         if (termsOfUseText != null) {
    1318             s.setTermsOfUseText(termsOfUseText);
    1319         }
    1320         if (termsOfUseURL != null) {
    1321             if ("osm".equals(termsOfUseURL)) {
    1322                 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
    1323             } else {
    1324                 s.setTermsOfUseURL(termsOfUseURL);
    1325             }
    1326         }
    1327     }
    1328 
    1329     /**
    1330      * Returns the imagery type.
    1331      * @return The imagery type
    1332      */
    1333     public ImageryType getImageryType() {
    1334         return imageryType;
    1335     }
    1336 
    1337     /**
    1338      * Sets the imagery type.
    1339      * @param imageryType The imagery type
    1340      */
    1341     public void setImageryType(ImageryType imageryType) {
    1342         this.imageryType = imageryType;
    1343     }
    1344 
    1345     /**
    1346      * Returns the imagery category.
    1347      * @return The imagery category
    1348      * @since 13792
    1349      */
    1350     public ImageryCategory getImageryCategory() {
    1351         return category;
    1352     }
    1353 
    1354     /**
    1355      * Sets the imagery category.
    1356      * @param category The imagery category
    1357      * @since 13792
    1358      */
    1359     public void setImageryCategory(ImageryCategory category) {
    1360         this.category = category;
    1361     }
    1362 
    1363     /**
    1364      * Returns the imagery category original string (don't use except for error checks).
    1365      * @return The imagery category original string
    1366      * @since 13792
    1367      */
    1368     public String getImageryCategoryOriginalString() {
    1369         return categoryOriginalString;
    1370     }
    1371 
    1372     /**
    1373      * Sets the imagery category original string (don't use except for error checks).
    1374      * @param categoryOriginalString The imagery category original string
    1375      * @since 13792
    1376      */
    1377     public void setImageryCategoryOriginalString(String categoryOriginalString) {
    1378         this.categoryOriginalString = intern(categoryOriginalString);
    1379     }
    1380 
    1381     /**
    1382      * Returns true if this layer's URL is matched by one of the regular
    1383      * expressions kept by the current OsmApi instance.
    1384      * @return {@code true} is this entry is blacklisted, {@code false} otherwise
    1385      */
    1386     public boolean isBlacklisted() {
    1387         Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
    1388         return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
    1389     }
    1390 
    1391     /**
    1392      * Sets the map of &lt;header name, header value&gt; that if any of this header
    1393      * will be returned, then this tile will be treated as "no tile at this zoom level"
    1394      *
    1395      * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
    1396      * @since 9613
    1397      */
    1398     public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
    1399        if (noTileHeaders == null || noTileHeaders.isEmpty()) {
    1400            this.noTileHeaders = null;
    1401        } else {
    1402             this.noTileHeaders = noTileHeaders.toMap();
    1403        }
    1404     }
    1405 
    1406     @Override
    1407     public Map<String, Set<String>> getNoTileHeaders() {
    1408         return noTileHeaders;
    1409     }
    1410 
    1411     /**
    1412      * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
    1413      * will be returned, then this tile will be treated as "no tile at this zoom level"
    1414      *
    1415      * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
    1416      * @since 9613
    1417      */
    1418     public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
    1419         if (noTileChecksums == null || noTileChecksums.isEmpty()) {
    1420             this.noTileChecksums = null;
    1421         } else {
    1422             this.noTileChecksums = noTileChecksums.toMap();
    1423         }
    1424     }
    1425 
    1426     @Override
    1427     public Map<String, Set<String>> getNoTileChecksums() {
    1428         return noTileChecksums;
    1429     }
    1430 
    1431     /**
    1432      * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
    1433      * be moved to metadata
    1434      *
    1435      * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
    1436      * @since 8418
    1437      */
    1438     public void setMetadataHeaders(Map<String, String> metadataHeaders) {
    1439         if (metadataHeaders == null || metadataHeaders.isEmpty()) {
    1440             this.metadataHeaders = null;
    1441         } else {
    1442             this.metadataHeaders = metadataHeaders;
    1443         }
    1444     }
    1445 
    1446     /**
    1447771     * Gets the flag if the georeference is valid.
    1448772     * @return <code>true</code> if it is valid.
    1449773     */
     
    1496820    }
    1497821
    1498822    /**
    1499      * Adds an old Id.
    1500      *
    1501      * @param id the Id to be added
    1502      * @since 13536
    1503      */
    1504     public void addOldId(String id) {
    1505        if (oldIds == null) {
    1506            oldIds = new ArrayList<>();
    1507        }
    1508        oldIds.add(id);
    1509     }
    1510 
    1511     /**
    1512      * Get old Ids.
    1513      *
    1514      * @return collection of ids
    1515      * @since 13536
    1516      */
    1517     public Collection<String> getOldIds() {
    1518         return oldIds;
    1519     }
    1520 
    1521     /**
    1522      * Adds a mirror entry. Mirror entries are completed with the data from the master entry
    1523      * and only describe another method to access identical data.
    1524      *
    1525      * @param entry the mirror to be added
    1526      * @since 9658
    1527      */
    1528     public void addMirror(ImageryInfo entry) {
    1529        if (mirrors == null) {
    1530            mirrors = new ArrayList<>();
    1531        }
    1532        mirrors.add(entry);
    1533     }
    1534 
    1535     /**
    1536      * Returns the mirror entries. Entries are completed with master entry data.
    1537      *
    1538      * @return the list of mirrors
    1539      * @since 9658
    1540      */
    1541     public List<ImageryInfo> getMirrors() {
    1542        List<ImageryInfo> l = new ArrayList<>();
    1543        if (mirrors != null) {
    1544            int num = 1;
    1545            for (ImageryInfo i : mirrors) {
    1546                ImageryInfo n = new ImageryInfo(this);
    1547                if (i.defaultMaxZoom != 0) {
    1548                    n.defaultMaxZoom = i.defaultMaxZoom;
    1549                }
    1550                if (i.defaultMinZoom != 0) {
    1551                    n.defaultMinZoom = i.defaultMinZoom;
    1552                }
    1553                n.setServerProjections(i.getServerProjections());
    1554                n.url = i.url;
    1555                n.imageryType = i.imageryType;
    1556                if (i.getTileSize() != 0) {
    1557                    n.setTileSize(i.getTileSize());
    1558                }
    1559                if (i.getPrivacyPolicyURL() != null) {
    1560                    n.setPrivacyPolicyURL(i.getPrivacyPolicyURL());
    1561                }
    1562                if (n.id != null) {
    1563                    n.id = n.id + "_mirror"+num;
    1564                }
    1565                if (num > 1) {
    1566                    n.name = tr("{0} mirror server {1}", n.name, num);
    1567                    if (n.origName != null) {
    1568                        n.origName += " mirror server " + num;
    1569                    }
    1570                } else {
    1571                    n.name = tr("{0} mirror server", n.name);
    1572                    if (n.origName != null) {
    1573                        n.origName += " mirror server";
    1574                    }
    1575                }
    1576                l.add(n);
    1577                ++num;
    1578            }
    1579        }
    1580        return l;
    1581     }
    1582 
    1583     /**
    1584      * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)
    1585      * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer
    1586      * to work on
    1587      * @return Collection of the layer names
    1588      */
    1589     public List<DefaultLayer> getDefaultLayers() {
    1590         return defaultLayers;
    1591     }
    1592 
    1593     /**
    1594      * Sets the default layers that user will work with
    1595      * @param layers set the list of default layers
    1596      */
    1597     public void setDefaultLayers(List<DefaultLayer> layers) {
    1598         this.defaultLayers = Utils.toUnmodifiableList(layers);
    1599     }
    1600 
    1601     /**
    1602      * Returns custom HTTP headers that should be sent with request towards imagery provider
    1603      * @return headers
    1604      */
    1605     public Map<String, String> getCustomHttpHeaders() {
    1606         return customHttpHeaders;
    1607     }
    1608 
    1609     /**
    1610      * Sets custom HTTP headers that should be sent with request towards imagery provider
    1611      * @param customHttpHeaders http headers
    1612      */
    1613     public void setCustomHttpHeaders(Map<String, String> customHttpHeaders) {
    1614         this.customHttpHeaders = Utils.toUnmodifiableMap(customHttpHeaders);
    1615     }
    1616 
    1617     /**
    1618823     * Determines if this imagery should be transparent.
    1619824     * @return should this imagery be transparent
    1620825     */
     
    1646851        this.minimumTileExpire = minimumTileExpire;
    1647852    }
    1648853
    1649     /**
    1650      * Get a string representation of this imagery info suitable for the {@code source} changeset tag.
    1651      * @return English name, if known
    1652      * @since 13890
    1653      */
    1654     public String getSourceName() {
    1655         if (ImageryType.BING == getImageryType()) {
    1656             return "Bing";
    1657         } else {
    1658             if (id != null) {
    1659                 // Retrieve english name, unfortunately not saved in preferences
    1660                 Optional<ImageryInfo> infoEn = ImageryLayerInfo.allDefaultLayers.stream().filter(x -> id.equals(x.getId())).findAny();
    1661                 if (infoEn.isPresent()) {
    1662                     return infoEn.get().getOriginalName();
    1663                 }
    1664             }
    1665             return getOriginalName();
    1666         }
    1667     }
    1668 
    1669     private static String intern(String string) {
    1670         return string == null ? null : string.intern();
    1671     }
    1672854}
  • src/org/openstreetmap/josm/data/sources/ICommonSource.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4/**
     5 * This interface is used to ensure that a class can get a enum from a string.
     6 * For various reasons, the fromString method cannot be implemented statically.
     7 *
     8 * @author Taylor Smock
     9 * @since xxx
     10 *
     11 * @param <T> The enum type
     12 */
     13public interface ICommonSource<T extends Enum<T>> {
     14    /**
     15     * Get the default value for the Enum
     16     * @return The default value
     17     */
     18    public T getDefault();
     19
     20    /**
     21     * Returns the source category from the given category string.
     22     * @param s The category string
     23     * @return the source category matching the given category string
     24     */
     25    public T fromString(String s);
     26}
  • src/org/openstreetmap/josm/data/sources/ISourceCategory.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import javax.swing.ImageIcon;
     5
     6import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
     7
     8/**
     9 * @author Taylor Smock
     10 *
     11 * @param <T> The enum that is extending this interface
     12 * @since xxx
     13 */
     14public interface ISourceCategory<T extends Enum<T>> extends ICommonSource<T> {
     15
     16    /**
     17     * Returns the unique string identifying this category.
     18     * @return the unique string identifying this category
     19     */
     20    public String getCategoryString();
     21
     22    /**
     23     * Returns the description of this category.
     24     * @return the description of this category
     25     */
     26    public String getDescription();
     27
     28    /**
     29     * Returns the category icon at the given size.
     30     * @param size icon wanted size
     31     * @return the category icon at the given size
     32     */
     33    public ImageIcon getIcon(ImageSizes size);
     34}
  • src/org/openstreetmap/josm/data/sources/ISourceType.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4/**
     5 * This interface should only be used for Enums
     6 * @author Taylor Smock
     7 * @since xxx
     8 *
     9 * @param <T> The source type (e.g., Imagery or otherwise -- should be the name of the class)
     10 */
     11public interface ISourceType<T extends Enum<T>> extends ICommonSource<T> {
     12
     13    /**
     14     * Returns the unique string identifying this type.
     15     * @return the unique string identifying this type
     16     */
     17    public String getTypeString();
     18}
  • src/org/openstreetmap/josm/data/sources/SourceBounds.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import java.util.ArrayList;
     5import java.util.List;
     6import java.util.Objects;
     7
     8import org.openstreetmap.josm.data.Bounds;
     9import org.openstreetmap.josm.data.imagery.Shape;
     10
     11/**
     12 *
     13 * Multi-polygon bounds for source backgrounds.
     14 * Used to display source coverage in preferences and to determine relevant source entries based on edit location.
     15 *
     16 * @author Frederik Ramm, extracted by Taylor Smock
     17 * @since xxx (extracted from {@link org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds})
     18 */
     19public class SourceBounds extends Bounds {
     20
     21    /**
     22     * Constructs a new {@code SourceBounds} from string.
     23     * @param asString The string containing the list of shapes defining this bounds
     24     * @param separator The shape separator in the given string, usually a comma
     25     */
     26    public SourceBounds(String asString, String separator) {
     27        super(asString, separator);
     28    }
     29
     30    private List<Shape> shapes = new ArrayList<>();
     31
     32    /**
     33     * Adds a new shape to this bounds.
     34     * @param shape The shape to add
     35     */
     36    public final void addShape(Shape shape) {
     37        this.shapes.add(shape);
     38    }
     39
     40    /**
     41     * Sets the list of shapes defining this bounds.
     42     * @param shapes The list of shapes defining this bounds.
     43     */
     44    public final void setShapes(List<Shape> shapes) {
     45        this.shapes = shapes;
     46    }
     47
     48    /**
     49     * Returns the list of shapes defining this bounds.
     50     * @return The list of shapes defining this bounds
     51     */
     52    public final List<Shape> getShapes() {
     53        return shapes;
     54    }
     55
     56    @Override
     57    public int hashCode() {
     58        return Objects.hash(super.hashCode(), shapes);
     59    }
     60
     61    @Override
     62    public boolean equals(Object o) {
     63        if (this == o) return true;
     64        if (o == null || getClass() != o.getClass()) return false;
     65        if (!super.equals(o)) return false;
     66        SourceBounds that = (SourceBounds) o;
     67        return Objects.equals(shapes, that.shapes);
     68    }
     69}
  • src/org/openstreetmap/josm/data/sources/SourceInfo.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.Image;
     7import java.lang.reflect.ParameterizedType;
     8import java.util.ArrayList;
     9import java.util.Collection;
     10import java.util.Collections;
     11import java.util.HashMap;
     12import java.util.List;
     13import java.util.Locale;
     14import java.util.Map;
     15import java.util.Objects;
     16import java.util.Optional;
     17import java.util.Set;
     18import java.util.TreeSet;
     19
     20import javax.swing.ImageIcon;
     21
     22import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
     23import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
     24import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
     25import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
     26import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
     27import org.openstreetmap.josm.data.StructUtils;
     28import org.openstreetmap.josm.data.imagery.DefaultLayer;
     29import org.openstreetmap.josm.data.imagery.ImageryInfo;
     30import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
     31import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
     32import org.openstreetmap.josm.io.Capabilities;
     33import org.openstreetmap.josm.io.OsmApi;
     34import org.openstreetmap.josm.spi.preferences.Config;
     35import org.openstreetmap.josm.spi.preferences.IPreferences;
     36import org.openstreetmap.josm.tools.ImageProvider;
     37import org.openstreetmap.josm.tools.LanguageInfo;
     38import org.openstreetmap.josm.tools.MultiMap;
     39import org.openstreetmap.josm.tools.Utils;
     40
     41/**
     42 * @author Taylor Smock
     43 * @param <T> The SourceCategory type
     44 * @param <U> The SourceType
     45 * @param <V> The SourceBounds
     46 *
     47 * @since xxx
     48 */
     49public class SourceInfo<T extends ISourceCategory<?>, U extends ISourceType<?>, V extends SourceBounds, W extends SourcePreferenceEntry<?>> extends TileSourceInfo implements Comparable<SourceInfo<T, U, V, W>>, Attributed {
     50    /** original name of the source entry in case of translation call, for multiple languages English when possible */
     51    protected String origName;
     52    /** (original) language of the translated name entry */
     53    protected String langName;
     54    /** whether this is a entry activated by default or not */
     55    protected boolean defaultEntry;
     56    /** Whether this service requires a explicit EULA acceptance before it can be activated */
     57    protected String eulaAcceptanceRequired;
     58    /** type of the services - WMS, TMS, ... */
     59    @SuppressWarnings("unchecked")
     60    protected U sourceType = (U) ((U) ((Enum<?>)((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).getDeclaringClass().getEnumConstants()[0]).getDefault();
     61    /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */
     62    protected V bounds;
     63    /** description of the imagery entry, should contain notes what type of data it is */
     64    protected String description;
     65    /** language of the description entry */
     66    protected String langDescription;
     67    /** Text of a text attribution displayed when using the imagery */
     68    protected String attributionText;
     69    /** Link to the privacy policy of the operator */
     70    protected String privacyPolicyURL;
     71    /** Link to a reference stating the permission for OSM usage */
     72    protected String permissionReferenceURL;
     73    /** Link behind the text attribution displayed when using the imagery */
     74    protected String attributionLinkURL;
     75    /** Image of a graphical attribution displayed when using the imagery */
     76    protected String attributionImage;
     77    /** Link behind the graphical attribution displayed when using the imagery */
     78    protected String attributionImageURL;
     79    /** Text with usage terms displayed when using the imagery */
     80    protected String termsOfUseText;
     81    /** Link behind the text with usage terms displayed when using the imagery */
     82    protected String termsOfUseURL;
     83    /** country code of the imagery (for country specific imagery) */
     84    protected String countryCode = "";
     85    /**
     86      * creation date of the source (in the form YYYY-MM-DD;YYYY-MM-DD, where
     87      * DD and MM as well as a second date are optional).
     88      *
     89      * Also used as time filter for WMS time={time} parameter (such as Sentinel-2)
     90      * @since 11570
     91      */
     92    protected String date;
     93    /**
     94      * list of old IDs, only for loading, not handled anywhere else
     95      * @since 13536
     96      */
     97    protected Collection<String> oldIds;
     98    /** mirrors of different type for this entry */
     99    protected List<SourceInfo<T, U, V, W>> mirrors;
     100    /** icon used in menu */
     101    protected String icon;
     102    /** which layers should be activated by default on layer addition. **/
     103    protected List<DefaultLayer> defaultLayers = Collections.emptyList();
     104    /** HTTP headers **/
     105    protected Map<String, String> customHttpHeaders = Collections.emptyMap();
     106    /** category of the imagery */
     107    protected T category;
     108    /** category of the imagery (input string, not saved, copied or used otherwise except for error checks) */
     109    protected String categoryOriginalString;
     110    /** when adding a field, also adapt the:
     111     * {@link #ImageryPreferenceEntry ImageryPreferenceEntry object}
     112     * {@link #ImageryPreferenceEntry#ImageryPreferenceEntry(ImageryInfo) ImageryPreferenceEntry constructor}
     113     * {@link #ImageryInfo(ImageryPreferenceEntry) ImageryInfo constructor}
     114     * {@link #ImageryInfo(ImageryInfo) ImageryInfo constructor}
     115     * {@link #equalsPref(ImageryPreferenceEntry) equalsPref method}
     116     **/
     117
     118    /**
     119     * Creates empty SourceInfo class
     120     */
     121    public SourceInfo() {
     122        super();
     123    }
     124
     125    /**
     126     * Create a SourceInfo class
     127     *
     128     * @param name name
     129     */
     130    public SourceInfo(String name) {
     131        super(name);
     132    }
     133
     134    /**
     135     * Create a SourceInfo class
     136     *
     137     * @param name name
     138     * @param url base URL
     139     * @param id unique id
     140     */
     141    public SourceInfo(String name, String url, String id) {
     142        super(name, url, id);
     143    }
     144
     145
     146    @Override
     147    public int hashCode() {
     148        return Objects.hash(url, sourceType);
     149    }
     150
     151    /**
     152     * Check if this object equals another SourceInfo with respect to the properties
     153     * that get written to the preference file.
     154     *
     155     * This should be overridden and called in subclasses.
     156     *
     157     * @param other the SourceInfo object to compare to
     158     * @return true if they are equal
     159     */
     160    public boolean equalsPref(SourceInfo<T, U, V, W> other) {
     161        if (other == null) {
     162            return false;
     163        }
     164
     165        // CHECKSTYLE.OFF: BooleanExpressionComplexity
     166        return
     167                Objects.equals(this.name, other.name) &&
     168                Objects.equals(this.id, other.id) &&
     169                Objects.equals(this.url, other.url) &&
     170                Objects.equals(this.modTileFeatures, other.modTileFeatures) &&
     171                Objects.equals(this.cookies, other.cookies) &&
     172                Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
     173                Objects.equals(this.sourceType, other.sourceType) &&
     174                Objects.equals(this.bounds, other.bounds) &&
     175                Objects.equals(this.attributionText, other.attributionText) &&
     176                Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
     177                Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) &&
     178                Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
     179                Objects.equals(this.attributionImage, other.attributionImage) &&
     180                Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
     181                Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
     182                Objects.equals(this.countryCode, other.countryCode) &&
     183                Objects.equals(this.date, other.date) &&
     184                Objects.equals(this.icon, other.icon) &&
     185                Objects.equals(this.description, other.description) &&
     186                Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
     187                Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
     188                Objects.equals(this.metadataHeaders, other.metadataHeaders) &&
     189                Objects.equals(this.defaultLayers, other.defaultLayers) &&
     190                Objects.equals(this.customHttpHeaders, other.customHttpHeaders) &&
     191                Objects.equals(this.category, other.category);
     192        // CHECKSTYLE.ON: BooleanExpressionComplexity
     193    }
     194
     195    @Override
     196    public boolean equals(Object o) {
     197        if (this == o) return true;
     198        if (o == null || getClass() != o.getClass()) return false;
     199        ImageryInfo that = (ImageryInfo) o;
     200        return sourceType == that.sourceType && Objects.equals(url, that.url);
     201    }
     202
     203    private static final Map<String, String> localizedCountriesCache = new HashMap<>();
     204    static {
     205        localizedCountriesCache.put("", tr("Worldwide"));
     206    }
     207
     208    /**
     209     * Returns a localized name for the given country code, or "Worldwide" if empty.
     210     * This function falls back on the English name, and uses the ISO code as a last-resortvalue.
     211     *
     212     * @param countryCode An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code
     213     * @return The name of the country appropriate to the current locale.
     214     * @see Locale#getDisplayCountry
     215     * @since 15158
     216     */
     217    public static String getLocalizedCountry(String countryCode) {
     218        return localizedCountriesCache.computeIfAbsent(countryCode, code -> new Locale("en", code).getDisplayCountry());
     219    }
     220
     221    @Override
     222    public String toString() {
     223        // Used in imagery preferences filtering, so must be efficient
     224        return new StringBuilder(name)
     225                .append('[').append(countryCode)
     226                // appending the localized country in toString() allows us to filter imagery preferences table with it!
     227                .append("] ('").append(getLocalizedCountry(countryCode)).append(')')
     228                .append(" - ").append(url)
     229                .append(" - ").append(sourceType)
     230                .toString();
     231    }
     232
     233    @Override
     234    public int compareTo(SourceInfo<T, U, V, W> in) {
     235        int i = countryCode.compareTo(in.countryCode);
     236        if (i == 0) {
     237            i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
     238        }
     239        if (i == 0) {
     240            i = url.compareTo(in.url);
     241        }
     242        return i;
     243    }
     244
     245    /**
     246     * Determines if URL is equal to given imagery info.
     247     * @param in imagery info
     248     * @return {@code true} if URL is equal to given imagery info
     249     */
     250    public boolean equalsBaseValues(ImageryInfo in) {
     251        return url.equals(in.url);
     252    }
     253
     254    /**
     255     * Sets the source polygonial bounds.
     256     * @param b The source bounds (non-rectangular)
     257     */
     258    public void setBounds(V b) {
     259        this.bounds = b;
     260    }
     261
     262    /**
     263     * Returns the source polygonial bounds.
     264     * @return The source bounds (non-rectangular)
     265     */
     266    public V getBounds() {
     267        return bounds;
     268    }
     269
     270    @Override
     271    public boolean requiresAttribution() {
     272        return attributionText != null || attributionLinkURL != null || attributionImage != null
     273                || termsOfUseText != null || termsOfUseURL != null;
     274    }
     275
     276    @Override
     277    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
     278        return attributionText;
     279    }
     280
     281    @Override
     282    public String getAttributionLinkURL() {
     283        return attributionLinkURL;
     284    }
     285
     286    /**
     287     * Return the permission reference URL.
     288     * @return The url
     289     * @see #setPermissionReferenceURL
     290     * @since 11975
     291     */
     292    public String getPermissionReferenceURL() {
     293        return permissionReferenceURL;
     294    }
     295
     296    /**
     297     * Return the privacy policy URL.
     298     * @return The url
     299     * @see #setPrivacyPolicyURL
     300     * @since 16127
     301     */
     302    public String getPrivacyPolicyURL() {
     303        return privacyPolicyURL;
     304    }
     305
     306    @Override
     307    public Image getAttributionImage() {
     308        ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
     309        if (i != null) {
     310            return i.getImage();
     311        }
     312        return null;
     313    }
     314
     315    /**
     316     * Return the raw attribution logo information (an URL to the image).
     317     * @return The url text
     318     * @since 12257
     319     */
     320    public String getAttributionImageRaw() {
     321        return attributionImage;
     322    }
     323
     324    @Override
     325    public String getAttributionImageURL() {
     326        return attributionImageURL;
     327    }
     328
     329    @Override
     330    public String getTermsOfUseText() {
     331        return termsOfUseText;
     332    }
     333
     334    @Override
     335    public String getTermsOfUseURL() {
     336        return termsOfUseURL;
     337    }
     338
     339    /**
     340     * Set the attribution text
     341     * @param text The text
     342     * @see #getAttributionText(int, ICoordinate, ICoordinate)
     343     */
     344    public void setAttributionText(String text) {
     345        attributionText = intern(text);
     346    }
     347
     348    /**
     349     * Set the attribution image
     350     * @param url The url of the image.
     351     * @see #getAttributionImageURL()
     352     */
     353    public void setAttributionImageURL(String url) {
     354        attributionImageURL = url;
     355    }
     356
     357    /**
     358     * Set the image for the attribution
     359     * @param res The image resource
     360     * @see #getAttributionImage()
     361     */
     362    public void setAttributionImage(String res) {
     363        attributionImage = res;
     364    }
     365
     366    /**
     367     * Sets the URL the attribution should link to.
     368     * @param url The url.
     369     * @see #getAttributionLinkURL()
     370     */
     371    public void setAttributionLinkURL(String url) {
     372        attributionLinkURL = url;
     373    }
     374
     375    /**
     376     * Sets the permission reference URL.
     377     * @param url The url.
     378     * @see #getPermissionReferenceURL()
     379     * @since 11975
     380     */
     381    public void setPermissionReferenceURL(String url) {
     382        permissionReferenceURL = url;
     383    }
     384
     385    /**
     386     * Sets the privacy policy URL.
     387     * @param url The url.
     388     * @see #getPrivacyPolicyURL()
     389     * @since 16127
     390     */
     391    public void setPrivacyPolicyURL(String url) {
     392        privacyPolicyURL = url;
     393    }
     394
     395    /**
     396     * Sets the text to display to the user as terms of use.
     397     * @param text The text
     398     * @see #getTermsOfUseText()
     399     */
     400    public void setTermsOfUseText(String text) {
     401        termsOfUseText = text;
     402    }
     403
     404    /**
     405     * Sets a url that links to the terms of use text.
     406     * @param text The url.
     407     * @see #getTermsOfUseURL()
     408     */
     409    public void setTermsOfUseURL(String text) {
     410        termsOfUseURL = text;
     411    }
     412
     413    /**
     414     * Returns the entry name.
     415     * @return The entry name
     416     * @since 6968
     417     */
     418    public String getOriginalName() {
     419        return this.origName != null ? this.origName : this.name;
     420    }
     421
     422    /**
     423     * Sets the entry name and handle translation.
     424     * @param language The used language
     425     * @param name The entry name
     426     * @since 8091
     427     */
     428    public void setName(String language, String name) {
     429        boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
     430        if (LanguageInfo.isBetterLanguage(langName, language)) {
     431            this.name = isdefault ? tr(name) : name;
     432            this.langName = language;
     433        }
     434        if (origName == null || isdefault) {
     435            this.origName = name;
     436        }
     437    }
     438
     439    /**
     440     * Store the id of this info to the preferences and clear it afterwards.
     441     */
     442    public void clearId() {
     443        if (this.id != null) {
     444            Collection<String> newAddedIds = new TreeSet<>(Config.getPref().getList("imagery.layers.addedIds"));
     445            newAddedIds.add(this.id);
     446            Config.getPref().putList("imagery.layers.addedIds", new ArrayList<>(newAddedIds));
     447        }
     448        setId(null);
     449    }
     450
     451    /**
     452     * Determines if this entry is enabled by default.
     453     * @return {@code true} if this entry is enabled by default, {@code false} otherwise
     454     */
     455    public boolean isDefaultEntry() {
     456        return defaultEntry;
     457    }
     458
     459    /**
     460     * Sets the default state of this entry.
     461     * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
     462     */
     463    public void setDefaultEntry(boolean defaultEntry) {
     464        this.defaultEntry = defaultEntry;
     465    }
     466
     467    /**
     468     * Returns the description text when existing.
     469     * @return The description
     470     * @since 8065
     471     */
     472    public String getDescription() {
     473        return this.description;
     474    }
     475
     476    /**
     477     * Sets the description text when existing.
     478     * @param language The used language
     479     * @param description the imagery description text
     480     * @since 8091
     481     */
     482    public void setDescription(String language, String description) {
     483        boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
     484        if (LanguageInfo.isBetterLanguage(langDescription, language)) {
     485            this.description = isdefault ? tr(description) : description;
     486            this.langDescription = intern(language);
     487        }
     488    }
     489
     490    /**
     491     * Return the sorted list of activated Imagery IDs.
     492     * @return sorted list of activated Imagery IDs
     493     * @since 13536
     494     */
     495    public static <W> Collection<String> getActiveIds() {
     496        ArrayList<String> ids = new ArrayList<>();
     497        IPreferences pref = Config.getPref();
     498        if (pref != null) {
     499            List<W> entries = StructUtils.getListOfStructs(
     500                pref, "imagery.entries", null, W.class); // TODO
     501            if (entries != null) {
     502                for (W prefEntry : entries) {
     503                    if (prefEntry.id != null && !prefEntry.id.isEmpty())
     504                        ids.add(prefEntry.id);
     505                }
     506                Collections.sort(ids);
     507            }
     508        }
     509        return ids;
     510    }
     511
     512    /**
     513     * Returns a tool tip text for display.
     514     * @return The text
     515     * @since 8065
     516     */
     517    public String getToolTipText() {
     518        StringBuilder res = new StringBuilder(getName());
     519        boolean html = false;
     520        String dateStr = getDate();
     521        if (dateStr != null && !dateStr.isEmpty()) {
     522            res.append("<br>").append(tr("Date of imagery: {0}", dateStr));
     523            html = true;
     524        }
     525        if (category != null && category.getDescription() != null) {
     526            res.append("<br>").append(tr("Imagery category: {0}", category.getDescription()));
     527            html = true;
     528        }
     529        String desc = getDescription();
     530        if (desc != null && !desc.isEmpty()) {
     531            res.append("<br>").append(Utils.escapeReservedCharactersHTML(desc));
     532            html = true;
     533        }
     534        if (html) {
     535            res.insert(0, "<html>").append("</html>");
     536        }
     537        return res.toString();
     538    }
     539
     540    /**
     541     * Returns the EULA acceptance URL, if any.
     542     * @return The URL to an EULA text that has to be accepted before use, or {@code null}
     543     */
     544    public String getEulaAcceptanceRequired() {
     545        return eulaAcceptanceRequired;
     546    }
     547
     548    /**
     549     * Sets the EULA acceptance URL.
     550     * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
     551     */
     552    public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
     553        this.eulaAcceptanceRequired = eulaAcceptanceRequired;
     554    }
     555
     556    /**
     557     * Returns the ISO 3166-1-alpha-2 country code.
     558     * @return The country code (2 letters)
     559     */
     560    public String getCountryCode() {
     561        return countryCode;
     562    }
     563
     564    /**
     565     * Sets the ISO 3166-1-alpha-2 country code.
     566     * @param countryCode The country code (2 letters)
     567     */
     568    public void setCountryCode(String countryCode) {
     569        this.countryCode = intern(countryCode);
     570    }
     571
     572    /**
     573     * Returns the date information.
     574     * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where
     575     * DD and MM as well as a second date are optional)
     576     * @since 11570
     577     */
     578    public String getDate() {
     579        return date;
     580    }
     581
     582    /**
     583     * Sets the date information.
     584     * @param date The date information
     585     * @since 11570
     586     */
     587    public void setDate(String date) {
     588        this.date = date;
     589    }
     590
     591    /**
     592     * Returns the entry icon.
     593     * @return The entry icon
     594     */
     595    public String getIcon() {
     596        return icon;
     597    }
     598
     599    /**
     600     * Sets the entry icon.
     601     * @param icon The entry icon
     602     */
     603    public void setIcon(String icon) {
     604        this.icon = intern(icon);
     605    }
     606
     607    /**
     608     * Determines if this entry requires attribution.
     609     * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
     610     */
     611    public boolean hasAttribution() {
     612        return attributionText != null;
     613    }
     614
     615    /**
     616     * Copies attribution from another {@code ImageryInfo}.
     617     * @param i The other imagery info to get attribution from
     618     */
     619    public void copyAttribution(ImageryInfo i) {
     620        this.attributionImage = i.attributionImage;
     621        this.attributionImageURL = i.attributionImageURL;
     622        this.attributionText = i.attributionText;
     623        this.attributionLinkURL = i.attributionLinkURL;
     624        this.termsOfUseText = i.termsOfUseText;
     625        this.termsOfUseURL = i.termsOfUseURL;
     626    }
     627
     628    /**
     629     * Applies the attribution from this object to a tile source.
     630     * @param s The tile source
     631     */
     632    public void setAttribution(AbstractTileSource s) {
     633        if (attributionText != null) {
     634            if ("osm".equals(attributionText)) {
     635                s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
     636            } else {
     637                s.setAttributionText(attributionText);
     638            }
     639        }
     640        if (attributionLinkURL != null) {
     641            if ("osm".equals(attributionLinkURL)) {
     642                s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
     643            } else {
     644                s.setAttributionLinkURL(attributionLinkURL);
     645            }
     646        }
     647        if (attributionImage != null) {
     648            ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
     649            if (i != null) {
     650                s.setAttributionImage(i.getImage());
     651            }
     652        }
     653        if (attributionImageURL != null) {
     654            s.setAttributionImageURL(attributionImageURL);
     655        }
     656        if (termsOfUseText != null) {
     657            s.setTermsOfUseText(termsOfUseText);
     658        }
     659        if (termsOfUseURL != null) {
     660            if ("osm".equals(termsOfUseURL)) {
     661                s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
     662            } else {
     663                s.setTermsOfUseURL(termsOfUseURL);
     664            }
     665        }
     666    }
     667
     668    /**
     669     * Returns the source type.
     670     * @return The source type
     671     */
     672    public U getImageryType() { // TODO rename
     673        return sourceType;
     674    }
     675
     676    /**
     677     * Sets the source type.
     678     * @param imageryType The source type
     679     */
     680    public void setImageryType(U imageryType) { // TODO rename
     681        this.sourceType = imageryType;
     682    }
     683
     684    /**
     685     * Returns the imagery category.
     686     * @return The imagery category
     687     * @since 13792
     688     */
     689    public T getImageryCategory() { // TODO rename
     690        return category;
     691    }
     692
     693    /**
     694     * Sets the imagery category.
     695     * @param category The imagery category
     696     * @since 13792
     697     */
     698    public void setImageryCategory(T category) { // TODO rename
     699        this.category = category;
     700    }
     701
     702    /**
     703     * Returns the imagery category original string (don't use except for error checks).
     704     * @return The imagery category original string
     705     * @since 13792
     706     */
     707    public String getImageryCategoryOriginalString() {
     708        return categoryOriginalString;
     709    }
     710
     711    /**
     712     * Sets the imagery category original string (don't use except for error checks).
     713     * @param categoryOriginalString The imagery category original string
     714     * @since 13792
     715     */
     716    public void setImageryCategoryOriginalString(String categoryOriginalString) {
     717        this.categoryOriginalString = intern(categoryOriginalString);
     718    }
     719
     720    /**
     721     * Returns true if this layer's URL is matched by one of the regular
     722     * expressions kept by the current OsmApi instance.
     723     * @return {@code true} is this entry is blacklisted, {@code false} otherwise
     724     */
     725    public boolean isBlacklisted() {
     726        Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
     727        return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
     728    }
     729
     730    /**
     731     * Sets the map of &lt;header name, header value&gt; that if any of this header
     732     * will be returned, then this tile will be treated as "no tile at this zoom level"
     733     *
     734     * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
     735     * @since 9613
     736     */
     737    public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
     738       if (noTileHeaders == null || noTileHeaders.isEmpty()) {
     739           this.noTileHeaders = null;
     740       } else {
     741            this.noTileHeaders = noTileHeaders.toMap();
     742       }
     743    }
     744
     745    @Override
     746    public Map<String, Set<String>> getNoTileHeaders() {
     747        return noTileHeaders;
     748    }
     749
     750    /**
     751     * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
     752     * will be returned, then this tile will be treated as "no tile at this zoom level"
     753     *
     754     * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
     755     * @since 9613
     756     */
     757    public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
     758        if (noTileChecksums == null || noTileChecksums.isEmpty()) {
     759            this.noTileChecksums = null;
     760        } else {
     761            this.noTileChecksums = noTileChecksums.toMap();
     762        }
     763    }
     764
     765    @Override
     766    public Map<String, Set<String>> getNoTileChecksums() {
     767        return noTileChecksums;
     768    }
     769
     770    /**
     771     * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
     772     * be moved to metadata
     773     *
     774     * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
     775     * @since 8418
     776     */
     777    public void setMetadataHeaders(Map<String, String> metadataHeaders) {
     778        if (metadataHeaders == null || metadataHeaders.isEmpty()) {
     779            this.metadataHeaders = null;
     780        } else {
     781            this.metadataHeaders = metadataHeaders;
     782        }
     783    }
     784
     785    /**
     786     * Adds an old Id.
     787     *
     788     * @param id the Id to be added
     789     * @since 13536
     790     */
     791    public void addOldId(String id) {
     792       if (oldIds == null) {
     793           oldIds = new ArrayList<>();
     794       }
     795       oldIds.add(id);
     796    }
     797
     798    /**
     799     * Get old Ids.
     800     *
     801     * @return collection of ids
     802     * @since 13536
     803     */
     804    public Collection<String> getOldIds() {
     805        return oldIds;
     806    }
     807
     808    /**
     809     * Adds a mirror entry. Mirror entries are completed with the data from the master entry
     810     * and only describe another method to access identical data.
     811     *
     812     * @param entry the mirror to be added
     813     * @since 9658
     814     */
     815    public void addMirror(SourceInfo<T, U, V, W> entry) {
     816       if (mirrors == null) {
     817           mirrors = new ArrayList<>();
     818       }
     819       mirrors.add(entry);
     820    }
     821
     822    /**
     823     * Returns the mirror entries. Entries are completed with master entry data.
     824     *
     825     * @return the list of mirrors
     826     * @since 9658
     827     */
     828    public List<SourceInfo<T, U, V, W>> getMirrors() {
     829       List<SourceInfo<T, U, V, W>> l = new ArrayList<>();
     830       if (mirrors != null) {
     831           int num = 1;
     832           for (SourceInfo<T, U, V, W> i : mirrors) {
     833               ImageryInfo n = new ImageryInfo(this);
     834               if (i.defaultMaxZoom != 0) {
     835                   n.defaultMaxZoom = i.defaultMaxZoom;
     836               }
     837               if (i.defaultMinZoom != 0) {
     838                   n.defaultMinZoom = i.defaultMinZoom;
     839               }
     840               n.setServerProjections(i.getServerProjections());
     841               n.url = i.url;
     842               n.sourceType = i.sourceType;
     843               if (i.getTileSize() != 0) {
     844                   n.setTileSize(i.getTileSize());
     845               }
     846               if (i.getPrivacyPolicyURL() != null) {
     847                   n.setPrivacyPolicyURL(i.getPrivacyPolicyURL());
     848               }
     849               if (n.id != null) {
     850                   n.id = n.id + "_mirror"+num;
     851               }
     852               if (num > 1) {
     853                   n.name = tr("{0} mirror server {1}", n.name, num);
     854                   if (n.origName != null) {
     855                       n.origName += " mirror server " + num;
     856                   }
     857               } else {
     858                   n.name = tr("{0} mirror server", n.name);
     859                   if (n.origName != null) {
     860                       n.origName += " mirror server";
     861                   }
     862               }
     863               l.add(n);
     864               ++num;
     865           }
     866       }
     867       return l;
     868    }
     869
     870    /**
     871     * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)
     872     * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer
     873     * to work on
     874     * @return Collection of the layer names
     875     */
     876    public List<DefaultLayer> getDefaultLayers() {
     877        return defaultLayers;
     878    }
     879
     880    /**
     881     * Sets the default layers that user will work with
     882     * @param layers set the list of default layers
     883     */
     884    public void setDefaultLayers(List<DefaultLayer> layers) {
     885        this.defaultLayers = Utils.toUnmodifiableList(layers);
     886    }
     887
     888    /**
     889     * Returns custom HTTP headers that should be sent with request towards imagery provider
     890     * @return headers
     891     */
     892    public Map<String, String> getCustomHttpHeaders() {
     893        return customHttpHeaders;
     894    }
     895
     896    /**
     897     * Sets custom HTTP headers that should be sent with request towards imagery provider
     898     * @param customHttpHeaders http headers
     899     */
     900    public void setCustomHttpHeaders(Map<String, String> customHttpHeaders) {
     901        this.customHttpHeaders = Utils.toUnmodifiableMap(customHttpHeaders);
     902    }
     903
     904    /**
     905     * Get a string representation of this imagery info suitable for the {@code source} changeset tag.
     906     * @return English name, if known
     907     * @since 13890
     908     */
     909    public String getSourceName() {
     910        if (ImageryType.BING == getImageryType()) {
     911            return "Bing";
     912        } else {
     913            if (id != null) {
     914                // Retrieve english name, unfortunately not saved in preferences
     915                Optional<SourceInfo<T, U, V, W>> infoEn = ImageryLayerInfo.allDefaultLayers.stream().filter(x -> id.equals(x.getId())).findAny();
     916                if (infoEn.isPresent()) {
     917                    return infoEn.get().getOriginalName();
     918                }
     919            }
     920            return getOriginalName();
     921        }
     922    }
     923
     924    protected static String intern(String string) {
     925        return string == null ? null : string.intern();
     926    }
     927}
  • src/org/openstreetmap/josm/data/sources/SourcePreferenceEntry.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import java.util.Map;
     5
     6import javax.json.stream.JsonCollectors;
     7
     8import org.openstreetmap.josm.data.StructUtils.StructEntry;
     9import org.openstreetmap.josm.data.imagery.DefaultLayer;
     10import org.openstreetmap.josm.data.imagery.Shape;
     11import org.openstreetmap.josm.tools.MultiMap;
     12
     13public class SourcePreferenceEntry<T extends SourceInfo<?, ?, ?, ?>> {
     14    @StructEntry String name;
     15    @StructEntry String d;
     16    @StructEntry String id;
     17    @StructEntry String type;
     18    @StructEntry String url;
     19    @StructEntry double pixel_per_eastnorth;
     20    @StructEntry String eula;
     21    @StructEntry String attribution_text;
     22    @StructEntry String attribution_url;
     23    @StructEntry String permission_reference_url;
     24    @StructEntry String logo_image;
     25    @StructEntry String logo_url;
     26    @StructEntry String terms_of_use_text;
     27    @StructEntry String terms_of_use_url;
     28    @StructEntry String country_code = "";
     29    @StructEntry String date;
     30    @StructEntry int max_zoom;
     31    @StructEntry int min_zoom;
     32    @StructEntry String cookies;
     33    @StructEntry String bounds;
     34    @StructEntry String shapes;
     35    @StructEntry String projections;
     36    @StructEntry String icon;
     37    @StructEntry String description;
     38    @StructEntry MultiMap<String, String> noTileHeaders;
     39    @StructEntry MultiMap<String, String> noTileChecksums;
     40    @StructEntry int tileSize = -1;
     41    @StructEntry Map<String, String> metadataHeaders;
     42    @StructEntry boolean valid_georeference;
     43    @StructEntry boolean bestMarked;
     44    @StructEntry boolean modTileFeatures;
     45    @StructEntry boolean overlay;
     46    @StructEntry String default_layers;
     47    @StructEntry Map<String, String> customHttpHeaders;
     48    @StructEntry boolean transparent;
     49    @StructEntry int minimumTileExpire;
     50    @StructEntry String category;
     51
     52    /**
     53     * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
     54     */
     55    public SourcePreferenceEntry() {
     56        // Do nothing
     57    }
     58
     59    /**
     60     * Constructs a new {@code ImageryPreferenceEntry} from a given {@code ImageryInfo}.
     61     * @param i The corresponding imagery info
     62     */
     63    public SourcePreferenceEntry(T i) {
     64        name = i.name;
     65        id = i.id;
     66        type = i.sourceType.getTypeString();
     67        url = i.url;
     68        pixel_per_eastnorth = i.pixelPerDegree;
     69        eula = i.eulaAcceptanceRequired;
     70        attribution_text = i.attributionText;
     71        attribution_url = i.attributionLinkURL;
     72        permission_reference_url = i.permissionReferenceURL;
     73        date = i.date;
     74        bestMarked = i.bestMarked;
     75        overlay = i.overlay;
     76        logo_image = i.attributionImage;
     77        logo_url = i.attributionImageURL;
     78        terms_of_use_text = i.termsOfUseText;
     79        terms_of_use_url = i.termsOfUseURL;
     80        country_code = i.countryCode;
     81        max_zoom = i.defaultMaxZoom;
     82        min_zoom = i.defaultMinZoom;
     83        cookies = i.cookies;
     84        icon = intern(i.icon);
     85        description = i.description;
     86        category = i.category != null ? i.category.getCategoryString() : null;
     87        if (i.bounds != null) {
     88            bounds = i.bounds.encodeAsString(",");
     89            StringBuilder shapesString = new StringBuilder();
     90            for (Shape s : i.bounds.getShapes()) {
     91                if (shapesString.length() > 0) {
     92                    shapesString.append(';');
     93                }
     94                shapesString.append(s.encodeAsString(","));
     95            }
     96            if (shapesString.length() > 0) {
     97                shapes = shapesString.toString();
     98            }
     99        }
     100        if (!i.serverProjections.isEmpty()) {
     101            projections = String.join(",", i.serverProjections);
     102        }
     103        if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
     104            noTileHeaders = new MultiMap<>(i.noTileHeaders);
     105        }
     106
     107        if (i.noTileChecksums != null && !i.noTileChecksums.isEmpty()) {
     108            noTileChecksums = new MultiMap<>(i.noTileChecksums);
     109        }
     110
     111        if (i.metadataHeaders != null && !i.metadataHeaders.isEmpty()) {
     112            metadataHeaders = i.metadataHeaders;
     113        }
     114
     115        tileSize = i.getTileSize();
     116
     117        valid_georeference = i.isGeoreferenceValid();
     118        modTileFeatures = i.isModTileFeatures();
     119        if (!i.defaultLayers.isEmpty()) {
     120            default_layers = i.defaultLayers.stream().map(DefaultLayer::toJson).collect(JsonCollectors.toJsonArray()).toString();
     121        }
     122        customHttpHeaders = i.customHttpHeaders;
     123        transparent = i.isTransparent();
     124        minimumTileExpire = i.minimumTileExpire;
     125    }
     126
     127    @Override
     128    public String toString();
     129}
  • src/org/openstreetmap/josm/data/sources/ICommonSource.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4/**
     5 * This interface is used to ensure that a class can get a enum from a string.
     6 * For various reasons, the fromString method cannot be implemented statically.
     7 *
     8 * @author Taylor Smock
     9 * @since xxx
     10 *
     11 * @param <T> The enum type
     12 */
     13public interface ICommonSource<T extends Enum<T>> {
     14    /**
     15     * Get the default value for the Enum
     16     * @return The default value
     17     */
     18    public T getDefault();
     19
     20    /**
     21     * Returns the source category from the given category string.
     22     * @param s The category string
     23     * @return the source category matching the given category string
     24     */
     25    public T fromString(String s);
     26}
  • src/org/openstreetmap/josm/data/sources/ISourceCategory.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import javax.swing.ImageIcon;
     5
     6import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
     7
     8/**
     9 * @author Taylor Smock
     10 *
     11 * @param <T> The enum that is extending this interface
     12 * @since xxx
     13 */
     14public interface ISourceCategory<T extends Enum<T>> extends ICommonSource<T> {
     15
     16    /**
     17     * Returns the unique string identifying this category.
     18     * @return the unique string identifying this category
     19     */
     20    public String getCategoryString();
     21
     22    /**
     23     * Returns the description of this category.
     24     * @return the description of this category
     25     */
     26    public String getDescription();
     27
     28    /**
     29     * Returns the category icon at the given size.
     30     * @param size icon wanted size
     31     * @return the category icon at the given size
     32     */
     33    public ImageIcon getIcon(ImageSizes size);
     34}
  • src/org/openstreetmap/josm/data/sources/ISourceType.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4/**
     5 * This interface should only be used for Enums
     6 * @author Taylor Smock
     7 * @since xxx
     8 *
     9 * @param <T> The source type (e.g., Imagery or otherwise -- should be the name of the class)
     10 */
     11public interface ISourceType<T extends Enum<T>> extends ICommonSource<T> {
     12
     13    /**
     14     * Returns the unique string identifying this type.
     15     * @return the unique string identifying this type
     16     */
     17    public String getTypeString();
     18}
  • src/org/openstreetmap/josm/data/sources/SourceBounds.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import java.util.ArrayList;
     5import java.util.List;
     6import java.util.Objects;
     7
     8import org.openstreetmap.josm.data.Bounds;
     9import org.openstreetmap.josm.data.imagery.Shape;
     10
     11/**
     12 *
     13 * Multi-polygon bounds for source backgrounds.
     14 * Used to display source coverage in preferences and to determine relevant source entries based on edit location.
     15 *
     16 * @author Frederik Ramm, extracted by Taylor Smock
     17 * @since xxx (extracted from {@link org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryBounds})
     18 */
     19public class SourceBounds extends Bounds {
     20
     21    /**
     22     * Constructs a new {@code SourceBounds} from string.
     23     * @param asString The string containing the list of shapes defining this bounds
     24     * @param separator The shape separator in the given string, usually a comma
     25     */
     26    public SourceBounds(String asString, String separator) {
     27        super(asString, separator);
     28    }
     29
     30    private List<Shape> shapes = new ArrayList<>();
     31
     32    /**
     33     * Adds a new shape to this bounds.
     34     * @param shape The shape to add
     35     */
     36    public final void addShape(Shape shape) {
     37        this.shapes.add(shape);
     38    }
     39
     40    /**
     41     * Sets the list of shapes defining this bounds.
     42     * @param shapes The list of shapes defining this bounds.
     43     */
     44    public final void setShapes(List<Shape> shapes) {
     45        this.shapes = shapes;
     46    }
     47
     48    /**
     49     * Returns the list of shapes defining this bounds.
     50     * @return The list of shapes defining this bounds
     51     */
     52    public final List<Shape> getShapes() {
     53        return shapes;
     54    }
     55
     56    @Override
     57    public int hashCode() {
     58        return Objects.hash(super.hashCode(), shapes);
     59    }
     60
     61    @Override
     62    public boolean equals(Object o) {
     63        if (this == o) return true;
     64        if (o == null || getClass() != o.getClass()) return false;
     65        if (!super.equals(o)) return false;
     66        SourceBounds that = (SourceBounds) o;
     67        return Objects.equals(shapes, that.shapes);
     68    }
     69}
  • src/org/openstreetmap/josm/data/sources/SourceInfo.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.awt.Image;
     7import java.lang.reflect.ParameterizedType;
     8import java.util.ArrayList;
     9import java.util.Collection;
     10import java.util.Collections;
     11import java.util.HashMap;
     12import java.util.List;
     13import java.util.Locale;
     14import java.util.Map;
     15import java.util.Objects;
     16import java.util.Optional;
     17import java.util.Set;
     18import java.util.TreeSet;
     19
     20import javax.swing.ImageIcon;
     21
     22import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
     23import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
     24import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
     25import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
     26import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo;
     27import org.openstreetmap.josm.data.StructUtils;
     28import org.openstreetmap.josm.data.imagery.DefaultLayer;
     29import org.openstreetmap.josm.data.imagery.ImageryInfo;
     30import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
     31import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
     32import org.openstreetmap.josm.io.Capabilities;
     33import org.openstreetmap.josm.io.OsmApi;
     34import org.openstreetmap.josm.spi.preferences.Config;
     35import org.openstreetmap.josm.spi.preferences.IPreferences;
     36import org.openstreetmap.josm.tools.ImageProvider;
     37import org.openstreetmap.josm.tools.LanguageInfo;
     38import org.openstreetmap.josm.tools.MultiMap;
     39import org.openstreetmap.josm.tools.Utils;
     40
     41/**
     42 * @author Taylor Smock
     43 * @param <T> The SourceCategory type
     44 * @param <U> The SourceType
     45 * @param <V> The SourceBounds
     46 *
     47 * @since xxx
     48 */
     49public class SourceInfo<T extends ISourceCategory<?>, U extends ISourceType<?>, V extends SourceBounds, W extends SourcePreferenceEntry<?>> extends TileSourceInfo implements Comparable<SourceInfo<T, U, V, W>>, Attributed {
     50    /** original name of the source entry in case of translation call, for multiple languages English when possible */
     51    protected String origName;
     52    /** (original) language of the translated name entry */
     53    protected String langName;
     54    /** whether this is a entry activated by default or not */
     55    protected boolean defaultEntry;
     56    /** Whether this service requires a explicit EULA acceptance before it can be activated */
     57    protected String eulaAcceptanceRequired;
     58    /** type of the services - WMS, TMS, ... */
     59    @SuppressWarnings("unchecked")
     60    protected U sourceType = (U) ((U) ((Enum<?>)((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).getDeclaringClass().getEnumConstants()[0]).getDefault();
     61    /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */
     62    protected V bounds;
     63    /** description of the imagery entry, should contain notes what type of data it is */
     64    protected String description;
     65    /** language of the description entry */
     66    protected String langDescription;
     67    /** Text of a text attribution displayed when using the imagery */
     68    protected String attributionText;
     69    /** Link to the privacy policy of the operator */
     70    protected String privacyPolicyURL;
     71    /** Link to a reference stating the permission for OSM usage */
     72    protected String permissionReferenceURL;
     73    /** Link behind the text attribution displayed when using the imagery */
     74    protected String attributionLinkURL;
     75    /** Image of a graphical attribution displayed when using the imagery */
     76    protected String attributionImage;
     77    /** Link behind the graphical attribution displayed when using the imagery */
     78    protected String attributionImageURL;
     79    /** Text with usage terms displayed when using the imagery */
     80    protected String termsOfUseText;
     81    /** Link behind the text with usage terms displayed when using the imagery */
     82    protected String termsOfUseURL;
     83    /** country code of the imagery (for country specific imagery) */
     84    protected String countryCode = "";
     85    /**
     86      * creation date of the source (in the form YYYY-MM-DD;YYYY-MM-DD, where
     87      * DD and MM as well as a second date are optional).
     88      *
     89      * Also used as time filter for WMS time={time} parameter (such as Sentinel-2)
     90      * @since 11570
     91      */
     92    protected String date;
     93    /**
     94      * list of old IDs, only for loading, not handled anywhere else
     95      * @since 13536
     96      */
     97    protected Collection<String> oldIds;
     98    /** mirrors of different type for this entry */
     99    protected List<SourceInfo<T, U, V, W>> mirrors;
     100    /** icon used in menu */
     101    protected String icon;
     102    /** which layers should be activated by default on layer addition. **/
     103    protected List<DefaultLayer> defaultLayers = Collections.emptyList();
     104    /** HTTP headers **/
     105    protected Map<String, String> customHttpHeaders = Collections.emptyMap();
     106    /** category of the imagery */
     107    protected T category;
     108    /** category of the imagery (input string, not saved, copied or used otherwise except for error checks) */
     109    protected String categoryOriginalString;
     110    /** when adding a field, also adapt the:
     111     * {@link #ImageryPreferenceEntry ImageryPreferenceEntry object}
     112     * {@link #ImageryPreferenceEntry#ImageryPreferenceEntry(ImageryInfo) ImageryPreferenceEntry constructor}
     113     * {@link #ImageryInfo(ImageryPreferenceEntry) ImageryInfo constructor}
     114     * {@link #ImageryInfo(ImageryInfo) ImageryInfo constructor}
     115     * {@link #equalsPref(ImageryPreferenceEntry) equalsPref method}
     116     **/
     117
     118    /**
     119     * Creates empty SourceInfo class
     120     */
     121    public SourceInfo() {
     122        super();
     123    }
     124
     125    /**
     126     * Create a SourceInfo class
     127     *
     128     * @param name name
     129     */
     130    public SourceInfo(String name) {
     131        super(name);
     132    }
     133
     134    /**
     135     * Create a SourceInfo class
     136     *
     137     * @param name name
     138     * @param url base URL
     139     * @param id unique id
     140     */
     141    public SourceInfo(String name, String url, String id) {
     142        super(name, url, id);
     143    }
     144
     145
     146    @Override
     147    public int hashCode() {
     148        return Objects.hash(url, sourceType);
     149    }
     150
     151    /**
     152     * Check if this object equals another SourceInfo with respect to the properties
     153     * that get written to the preference file.
     154     *
     155     * This should be overridden and called in subclasses.
     156     *
     157     * @param other the SourceInfo object to compare to
     158     * @return true if they are equal
     159     */
     160    public boolean equalsPref(SourceInfo<T, U, V, W> other) {
     161        if (other == null) {
     162            return false;
     163        }
     164
     165        // CHECKSTYLE.OFF: BooleanExpressionComplexity
     166        return
     167                Objects.equals(this.name, other.name) &&
     168                Objects.equals(this.id, other.id) &&
     169                Objects.equals(this.url, other.url) &&
     170                Objects.equals(this.modTileFeatures, other.modTileFeatures) &&
     171                Objects.equals(this.cookies, other.cookies) &&
     172                Objects.equals(this.eulaAcceptanceRequired, other.eulaAcceptanceRequired) &&
     173                Objects.equals(this.sourceType, other.sourceType) &&
     174                Objects.equals(this.bounds, other.bounds) &&
     175                Objects.equals(this.attributionText, other.attributionText) &&
     176                Objects.equals(this.attributionLinkURL, other.attributionLinkURL) &&
     177                Objects.equals(this.permissionReferenceURL, other.permissionReferenceURL) &&
     178                Objects.equals(this.attributionImageURL, other.attributionImageURL) &&
     179                Objects.equals(this.attributionImage, other.attributionImage) &&
     180                Objects.equals(this.termsOfUseText, other.termsOfUseText) &&
     181                Objects.equals(this.termsOfUseURL, other.termsOfUseURL) &&
     182                Objects.equals(this.countryCode, other.countryCode) &&
     183                Objects.equals(this.date, other.date) &&
     184                Objects.equals(this.icon, other.icon) &&
     185                Objects.equals(this.description, other.description) &&
     186                Objects.equals(this.noTileHeaders, other.noTileHeaders) &&
     187                Objects.equals(this.noTileChecksums, other.noTileChecksums) &&
     188                Objects.equals(this.metadataHeaders, other.metadataHeaders) &&
     189                Objects.equals(this.defaultLayers, other.defaultLayers) &&
     190                Objects.equals(this.customHttpHeaders, other.customHttpHeaders) &&
     191                Objects.equals(this.category, other.category);
     192        // CHECKSTYLE.ON: BooleanExpressionComplexity
     193    }
     194
     195    @Override
     196    public boolean equals(Object o) {
     197        if (this == o) return true;
     198        if (o == null || getClass() != o.getClass()) return false;
     199        ImageryInfo that = (ImageryInfo) o;
     200        return sourceType == that.sourceType && Objects.equals(url, that.url);
     201    }
     202
     203    private static final Map<String, String> localizedCountriesCache = new HashMap<>();
     204    static {
     205        localizedCountriesCache.put("", tr("Worldwide"));
     206    }
     207
     208    /**
     209     * Returns a localized name for the given country code, or "Worldwide" if empty.
     210     * This function falls back on the English name, and uses the ISO code as a last-resortvalue.
     211     *
     212     * @param countryCode An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code
     213     * @return The name of the country appropriate to the current locale.
     214     * @see Locale#getDisplayCountry
     215     * @since 15158
     216     */
     217    public static String getLocalizedCountry(String countryCode) {
     218        return localizedCountriesCache.computeIfAbsent(countryCode, code -> new Locale("en", code).getDisplayCountry());
     219    }
     220
     221    @Override
     222    public String toString() {
     223        // Used in imagery preferences filtering, so must be efficient
     224        return new StringBuilder(name)
     225                .append('[').append(countryCode)
     226                // appending the localized country in toString() allows us to filter imagery preferences table with it!
     227                .append("] ('").append(getLocalizedCountry(countryCode)).append(')')
     228                .append(" - ").append(url)
     229                .append(" - ").append(sourceType)
     230                .toString();
     231    }
     232
     233    @Override
     234    public int compareTo(SourceInfo<T, U, V, W> in) {
     235        int i = countryCode.compareTo(in.countryCode);
     236        if (i == 0) {
     237            i = name.toLowerCase(Locale.ENGLISH).compareTo(in.name.toLowerCase(Locale.ENGLISH));
     238        }
     239        if (i == 0) {
     240            i = url.compareTo(in.url);
     241        }
     242        return i;
     243    }
     244
     245    /**
     246     * Determines if URL is equal to given imagery info.
     247     * @param in imagery info
     248     * @return {@code true} if URL is equal to given imagery info
     249     */
     250    public boolean equalsBaseValues(ImageryInfo in) {
     251        return url.equals(in.url);
     252    }
     253
     254    /**
     255     * Sets the source polygonial bounds.
     256     * @param b The source bounds (non-rectangular)
     257     */
     258    public void setBounds(V b) {
     259        this.bounds = b;
     260    }
     261
     262    /**
     263     * Returns the source polygonial bounds.
     264     * @return The source bounds (non-rectangular)
     265     */
     266    public V getBounds() {
     267        return bounds;
     268    }
     269
     270    @Override
     271    public boolean requiresAttribution() {
     272        return attributionText != null || attributionLinkURL != null || attributionImage != null
     273                || termsOfUseText != null || termsOfUseURL != null;
     274    }
     275
     276    @Override
     277    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
     278        return attributionText;
     279    }
     280
     281    @Override
     282    public String getAttributionLinkURL() {
     283        return attributionLinkURL;
     284    }
     285
     286    /**
     287     * Return the permission reference URL.
     288     * @return The url
     289     * @see #setPermissionReferenceURL
     290     * @since 11975
     291     */
     292    public String getPermissionReferenceURL() {
     293        return permissionReferenceURL;
     294    }
     295
     296    /**
     297     * Return the privacy policy URL.
     298     * @return The url
     299     * @see #setPrivacyPolicyURL
     300     * @since 16127
     301     */
     302    public String getPrivacyPolicyURL() {
     303        return privacyPolicyURL;
     304    }
     305
     306    @Override
     307    public Image getAttributionImage() {
     308        ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
     309        if (i != null) {
     310            return i.getImage();
     311        }
     312        return null;
     313    }
     314
     315    /**
     316     * Return the raw attribution logo information (an URL to the image).
     317     * @return The url text
     318     * @since 12257
     319     */
     320    public String getAttributionImageRaw() {
     321        return attributionImage;
     322    }
     323
     324    @Override
     325    public String getAttributionImageURL() {
     326        return attributionImageURL;
     327    }
     328
     329    @Override
     330    public String getTermsOfUseText() {
     331        return termsOfUseText;
     332    }
     333
     334    @Override
     335    public String getTermsOfUseURL() {
     336        return termsOfUseURL;
     337    }
     338
     339    /**
     340     * Set the attribution text
     341     * @param text The text
     342     * @see #getAttributionText(int, ICoordinate, ICoordinate)
     343     */
     344    public void setAttributionText(String text) {
     345        attributionText = intern(text);
     346    }
     347
     348    /**
     349     * Set the attribution image
     350     * @param url The url of the image.
     351     * @see #getAttributionImageURL()
     352     */
     353    public void setAttributionImageURL(String url) {
     354        attributionImageURL = url;
     355    }
     356
     357    /**
     358     * Set the image for the attribution
     359     * @param res The image resource
     360     * @see #getAttributionImage()
     361     */
     362    public void setAttributionImage(String res) {
     363        attributionImage = res;
     364    }
     365
     366    /**
     367     * Sets the URL the attribution should link to.
     368     * @param url The url.
     369     * @see #getAttributionLinkURL()
     370     */
     371    public void setAttributionLinkURL(String url) {
     372        attributionLinkURL = url;
     373    }
     374
     375    /**
     376     * Sets the permission reference URL.
     377     * @param url The url.
     378     * @see #getPermissionReferenceURL()
     379     * @since 11975
     380     */
     381    public void setPermissionReferenceURL(String url) {
     382        permissionReferenceURL = url;
     383    }
     384
     385    /**
     386     * Sets the privacy policy URL.
     387     * @param url The url.
     388     * @see #getPrivacyPolicyURL()
     389     * @since 16127
     390     */
     391    public void setPrivacyPolicyURL(String url) {
     392        privacyPolicyURL = url;
     393    }
     394
     395    /**
     396     * Sets the text to display to the user as terms of use.
     397     * @param text The text
     398     * @see #getTermsOfUseText()
     399     */
     400    public void setTermsOfUseText(String text) {
     401        termsOfUseText = text;
     402    }
     403
     404    /**
     405     * Sets a url that links to the terms of use text.
     406     * @param text The url.
     407     * @see #getTermsOfUseURL()
     408     */
     409    public void setTermsOfUseURL(String text) {
     410        termsOfUseURL = text;
     411    }
     412
     413    /**
     414     * Returns the entry name.
     415     * @return The entry name
     416     * @since 6968
     417     */
     418    public String getOriginalName() {
     419        return this.origName != null ? this.origName : this.name;
     420    }
     421
     422    /**
     423     * Sets the entry name and handle translation.
     424     * @param language The used language
     425     * @param name The entry name
     426     * @since 8091
     427     */
     428    public void setName(String language, String name) {
     429        boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
     430        if (LanguageInfo.isBetterLanguage(langName, language)) {
     431            this.name = isdefault ? tr(name) : name;
     432            this.langName = language;
     433        }
     434        if (origName == null || isdefault) {
     435            this.origName = name;
     436        }
     437    }
     438
     439    /**
     440     * Store the id of this info to the preferences and clear it afterwards.
     441     */
     442    public void clearId() {
     443        if (this.id != null) {
     444            Collection<String> newAddedIds = new TreeSet<>(Config.getPref().getList("imagery.layers.addedIds"));
     445            newAddedIds.add(this.id);
     446            Config.getPref().putList("imagery.layers.addedIds", new ArrayList<>(newAddedIds));
     447        }
     448        setId(null);
     449    }
     450
     451    /**
     452     * Determines if this entry is enabled by default.
     453     * @return {@code true} if this entry is enabled by default, {@code false} otherwise
     454     */
     455    public boolean isDefaultEntry() {
     456        return defaultEntry;
     457    }
     458
     459    /**
     460     * Sets the default state of this entry.
     461     * @param defaultEntry {@code true} if this entry has to be enabled by default, {@code false} otherwise
     462     */
     463    public void setDefaultEntry(boolean defaultEntry) {
     464        this.defaultEntry = defaultEntry;
     465    }
     466
     467    /**
     468     * Returns the description text when existing.
     469     * @return The description
     470     * @since 8065
     471     */
     472    public String getDescription() {
     473        return this.description;
     474    }
     475
     476    /**
     477     * Sets the description text when existing.
     478     * @param language The used language
     479     * @param description the imagery description text
     480     * @since 8091
     481     */
     482    public void setDescription(String language, String description) {
     483        boolean isdefault = LanguageInfo.getJOSMLocaleCode(null).equals(language);
     484        if (LanguageInfo.isBetterLanguage(langDescription, language)) {
     485            this.description = isdefault ? tr(description) : description;
     486            this.langDescription = intern(language);
     487        }
     488    }
     489
     490    /**
     491     * Return the sorted list of activated Imagery IDs.
     492     * @return sorted list of activated Imagery IDs
     493     * @since 13536
     494     */
     495    public static <W> Collection<String> getActiveIds() {
     496        ArrayList<String> ids = new ArrayList<>();
     497        IPreferences pref = Config.getPref();
     498        if (pref != null) {
     499            List<W> entries = StructUtils.getListOfStructs(
     500                pref, "imagery.entries", null, W.class); // TODO
     501            if (entries != null) {
     502                for (W prefEntry : entries) {
     503                    if (prefEntry.id != null && !prefEntry.id.isEmpty())
     504                        ids.add(prefEntry.id);
     505                }
     506                Collections.sort(ids);
     507            }
     508        }
     509        return ids;
     510    }
     511
     512    /**
     513     * Returns a tool tip text for display.
     514     * @return The text
     515     * @since 8065
     516     */
     517    public String getToolTipText() {
     518        StringBuilder res = new StringBuilder(getName());
     519        boolean html = false;
     520        String dateStr = getDate();
     521        if (dateStr != null && !dateStr.isEmpty()) {
     522            res.append("<br>").append(tr("Date of imagery: {0}", dateStr));
     523            html = true;
     524        }
     525        if (category != null && category.getDescription() != null) {
     526            res.append("<br>").append(tr("Imagery category: {0}", category.getDescription()));
     527            html = true;
     528        }
     529        String desc = getDescription();
     530        if (desc != null && !desc.isEmpty()) {
     531            res.append("<br>").append(Utils.escapeReservedCharactersHTML(desc));
     532            html = true;
     533        }
     534        if (html) {
     535            res.insert(0, "<html>").append("</html>");
     536        }
     537        return res.toString();
     538    }
     539
     540    /**
     541     * Returns the EULA acceptance URL, if any.
     542     * @return The URL to an EULA text that has to be accepted before use, or {@code null}
     543     */
     544    public String getEulaAcceptanceRequired() {
     545        return eulaAcceptanceRequired;
     546    }
     547
     548    /**
     549     * Sets the EULA acceptance URL.
     550     * @param eulaAcceptanceRequired The URL to an EULA text that has to be accepted before use
     551     */
     552    public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
     553        this.eulaAcceptanceRequired = eulaAcceptanceRequired;
     554    }
     555
     556    /**
     557     * Returns the ISO 3166-1-alpha-2 country code.
     558     * @return The country code (2 letters)
     559     */
     560    public String getCountryCode() {
     561        return countryCode;
     562    }
     563
     564    /**
     565     * Sets the ISO 3166-1-alpha-2 country code.
     566     * @param countryCode The country code (2 letters)
     567     */
     568    public void setCountryCode(String countryCode) {
     569        this.countryCode = intern(countryCode);
     570    }
     571
     572    /**
     573     * Returns the date information.
     574     * @return The date (in the form YYYY-MM-DD;YYYY-MM-DD, where
     575     * DD and MM as well as a second date are optional)
     576     * @since 11570
     577     */
     578    public String getDate() {
     579        return date;
     580    }
     581
     582    /**
     583     * Sets the date information.
     584     * @param date The date information
     585     * @since 11570
     586     */
     587    public void setDate(String date) {
     588        this.date = date;
     589    }
     590
     591    /**
     592     * Returns the entry icon.
     593     * @return The entry icon
     594     */
     595    public String getIcon() {
     596        return icon;
     597    }
     598
     599    /**
     600     * Sets the entry icon.
     601     * @param icon The entry icon
     602     */
     603    public void setIcon(String icon) {
     604        this.icon = intern(icon);
     605    }
     606
     607    /**
     608     * Determines if this entry requires attribution.
     609     * @return {@code true} if some attribution text has to be displayed, {@code false} otherwise
     610     */
     611    public boolean hasAttribution() {
     612        return attributionText != null;
     613    }
     614
     615    /**
     616     * Copies attribution from another {@code ImageryInfo}.
     617     * @param i The other imagery info to get attribution from
     618     */
     619    public void copyAttribution(ImageryInfo i) {
     620        this.attributionImage = i.attributionImage;
     621        this.attributionImageURL = i.attributionImageURL;
     622        this.attributionText = i.attributionText;
     623        this.attributionLinkURL = i.attributionLinkURL;
     624        this.termsOfUseText = i.termsOfUseText;
     625        this.termsOfUseURL = i.termsOfUseURL;
     626    }
     627
     628    /**
     629     * Applies the attribution from this object to a tile source.
     630     * @param s The tile source
     631     */
     632    public void setAttribution(AbstractTileSource s) {
     633        if (attributionText != null) {
     634            if ("osm".equals(attributionText)) {
     635                s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
     636            } else {
     637                s.setAttributionText(attributionText);
     638            }
     639        }
     640        if (attributionLinkURL != null) {
     641            if ("osm".equals(attributionLinkURL)) {
     642                s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
     643            } else {
     644                s.setAttributionLinkURL(attributionLinkURL);
     645            }
     646        }
     647        if (attributionImage != null) {
     648            ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
     649            if (i != null) {
     650                s.setAttributionImage(i.getImage());
     651            }
     652        }
     653        if (attributionImageURL != null) {
     654            s.setAttributionImageURL(attributionImageURL);
     655        }
     656        if (termsOfUseText != null) {
     657            s.setTermsOfUseText(termsOfUseText);
     658        }
     659        if (termsOfUseURL != null) {
     660            if ("osm".equals(termsOfUseURL)) {
     661                s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
     662            } else {
     663                s.setTermsOfUseURL(termsOfUseURL);
     664            }
     665        }
     666    }
     667
     668    /**
     669     * Returns the source type.
     670     * @return The source type
     671     */
     672    public U getImageryType() { // TODO rename
     673        return sourceType;
     674    }
     675
     676    /**
     677     * Sets the source type.
     678     * @param imageryType The source type
     679     */
     680    public void setImageryType(U imageryType) { // TODO rename
     681        this.sourceType = imageryType;
     682    }
     683
     684    /**
     685     * Returns the imagery category.
     686     * @return The imagery category
     687     * @since 13792
     688     */
     689    public T getImageryCategory() { // TODO rename
     690        return category;
     691    }
     692
     693    /**
     694     * Sets the imagery category.
     695     * @param category The imagery category
     696     * @since 13792
     697     */
     698    public void setImageryCategory(T category) { // TODO rename
     699        this.category = category;
     700    }
     701
     702    /**
     703     * Returns the imagery category original string (don't use except for error checks).
     704     * @return The imagery category original string
     705     * @since 13792
     706     */
     707    public String getImageryCategoryOriginalString() {
     708        return categoryOriginalString;
     709    }
     710
     711    /**
     712     * Sets the imagery category original string (don't use except for error checks).
     713     * @param categoryOriginalString The imagery category original string
     714     * @since 13792
     715     */
     716    public void setImageryCategoryOriginalString(String categoryOriginalString) {
     717        this.categoryOriginalString = intern(categoryOriginalString);
     718    }
     719
     720    /**
     721     * Returns true if this layer's URL is matched by one of the regular
     722     * expressions kept by the current OsmApi instance.
     723     * @return {@code true} is this entry is blacklisted, {@code false} otherwise
     724     */
     725    public boolean isBlacklisted() {
     726        Capabilities capabilities = OsmApi.getOsmApi().getCapabilities();
     727        return capabilities != null && capabilities.isOnImageryBlacklist(this.url);
     728    }
     729
     730    /**
     731     * Sets the map of &lt;header name, header value&gt; that if any of this header
     732     * will be returned, then this tile will be treated as "no tile at this zoom level"
     733     *
     734     * @param noTileHeaders Map of &lt;header name, header value&gt; which will be treated as "no tile at this zoom level"
     735     * @since 9613
     736     */
     737    public void setNoTileHeaders(MultiMap<String, String> noTileHeaders) {
     738       if (noTileHeaders == null || noTileHeaders.isEmpty()) {
     739           this.noTileHeaders = null;
     740       } else {
     741            this.noTileHeaders = noTileHeaders.toMap();
     742       }
     743    }
     744
     745    @Override
     746    public Map<String, Set<String>> getNoTileHeaders() {
     747        return noTileHeaders;
     748    }
     749
     750    /**
     751     * Sets the map of &lt;checksum type, checksum value&gt; that if any tile with that checksum
     752     * will be returned, then this tile will be treated as "no tile at this zoom level"
     753     *
     754     * @param noTileChecksums Map of &lt;checksum type, checksum value&gt; which will be treated as "no tile at this zoom level"
     755     * @since 9613
     756     */
     757    public void setNoTileChecksums(MultiMap<String, String> noTileChecksums) {
     758        if (noTileChecksums == null || noTileChecksums.isEmpty()) {
     759            this.noTileChecksums = null;
     760        } else {
     761            this.noTileChecksums = noTileChecksums.toMap();
     762        }
     763    }
     764
     765    @Override
     766    public Map<String, Set<String>> getNoTileChecksums() {
     767        return noTileChecksums;
     768    }
     769
     770    /**
     771     * Returns the map of &lt;header name, metadata key&gt; indicating, which HTTP headers should
     772     * be moved to metadata
     773     *
     774     * @param metadataHeaders map of &lt;header name, metadata key&gt; indicating, which HTTP headers should be moved to metadata
     775     * @since 8418
     776     */
     777    public void setMetadataHeaders(Map<String, String> metadataHeaders) {
     778        if (metadataHeaders == null || metadataHeaders.isEmpty()) {
     779            this.metadataHeaders = null;
     780        } else {
     781            this.metadataHeaders = metadataHeaders;
     782        }
     783    }
     784
     785    /**
     786     * Adds an old Id.
     787     *
     788     * @param id the Id to be added
     789     * @since 13536
     790     */
     791    public void addOldId(String id) {
     792       if (oldIds == null) {
     793           oldIds = new ArrayList<>();
     794       }
     795       oldIds.add(id);
     796    }
     797
     798    /**
     799     * Get old Ids.
     800     *
     801     * @return collection of ids
     802     * @since 13536
     803     */
     804    public Collection<String> getOldIds() {
     805        return oldIds;
     806    }
     807
     808    /**
     809     * Adds a mirror entry. Mirror entries are completed with the data from the master entry
     810     * and only describe another method to access identical data.
     811     *
     812     * @param entry the mirror to be added
     813     * @since 9658
     814     */
     815    public void addMirror(SourceInfo<T, U, V, W> entry) {
     816       if (mirrors == null) {
     817           mirrors = new ArrayList<>();
     818       }
     819       mirrors.add(entry);
     820    }
     821
     822    /**
     823     * Returns the mirror entries. Entries are completed with master entry data.
     824     *
     825     * @return the list of mirrors
     826     * @since 9658
     827     */
     828    public List<SourceInfo<T, U, V, W>> getMirrors() {
     829       List<SourceInfo<T, U, V, W>> l = new ArrayList<>();
     830       if (mirrors != null) {
     831           int num = 1;
     832           for (SourceInfo<T, U, V, W> i : mirrors) {
     833               ImageryInfo n = new ImageryInfo(this);
     834               if (i.defaultMaxZoom != 0) {
     835                   n.defaultMaxZoom = i.defaultMaxZoom;
     836               }
     837               if (i.defaultMinZoom != 0) {
     838                   n.defaultMinZoom = i.defaultMinZoom;
     839               }
     840               n.setServerProjections(i.getServerProjections());
     841               n.url = i.url;
     842               n.sourceType = i.sourceType;
     843               if (i.getTileSize() != 0) {
     844                   n.setTileSize(i.getTileSize());
     845               }
     846               if (i.getPrivacyPolicyURL() != null) {
     847                   n.setPrivacyPolicyURL(i.getPrivacyPolicyURL());
     848               }
     849               if (n.id != null) {
     850                   n.id = n.id + "_mirror"+num;
     851               }
     852               if (num > 1) {
     853                   n.name = tr("{0} mirror server {1}", n.name, num);
     854                   if (n.origName != null) {
     855                       n.origName += " mirror server " + num;
     856                   }
     857               } else {
     858                   n.name = tr("{0} mirror server", n.name);
     859                   if (n.origName != null) {
     860                       n.origName += " mirror server";
     861                   }
     862               }
     863               l.add(n);
     864               ++num;
     865           }
     866       }
     867       return l;
     868    }
     869
     870    /**
     871     * Returns default layers that should be shown for this Imagery (if at all supported by imagery provider)
     872     * If no layer is set to default and there is more than one imagery available, then user will be asked to choose the layer
     873     * to work on
     874     * @return Collection of the layer names
     875     */
     876    public List<DefaultLayer> getDefaultLayers() {
     877        return defaultLayers;
     878    }
     879
     880    /**
     881     * Sets the default layers that user will work with
     882     * @param layers set the list of default layers
     883     */
     884    public void setDefaultLayers(List<DefaultLayer> layers) {
     885        this.defaultLayers = Utils.toUnmodifiableList(layers);
     886    }
     887
     888    /**
     889     * Returns custom HTTP headers that should be sent with request towards imagery provider
     890     * @return headers
     891     */
     892    public Map<String, String> getCustomHttpHeaders() {
     893        return customHttpHeaders;
     894    }
     895
     896    /**
     897     * Sets custom HTTP headers that should be sent with request towards imagery provider
     898     * @param customHttpHeaders http headers
     899     */
     900    public void setCustomHttpHeaders(Map<String, String> customHttpHeaders) {
     901        this.customHttpHeaders = Utils.toUnmodifiableMap(customHttpHeaders);
     902    }
     903
     904    /**
     905     * Get a string representation of this imagery info suitable for the {@code source} changeset tag.
     906     * @return English name, if known
     907     * @since 13890
     908     */
     909    public String getSourceName() {
     910        if (ImageryType.BING == getImageryType()) {
     911            return "Bing";
     912        } else {
     913            if (id != null) {
     914                // Retrieve english name, unfortunately not saved in preferences
     915                Optional<SourceInfo<T, U, V, W>> infoEn = ImageryLayerInfo.allDefaultLayers.stream().filter(x -> id.equals(x.getId())).findAny();
     916                if (infoEn.isPresent()) {
     917                    return infoEn.get().getOriginalName();
     918                }
     919            }
     920            return getOriginalName();
     921        }
     922    }
     923
     924    protected static String intern(String string) {
     925        return string == null ? null : string.intern();
     926    }
     927}
  • src/org/openstreetmap/josm/data/sources/SourcePreferenceEntry.java

     
     1// License: GPL. For details, see LICENSE file.
     2package org.openstreetmap.josm.data.sources;
     3
     4import java.util.Map;
     5
     6import javax.json.stream.JsonCollectors;
     7
     8import org.openstreetmap.josm.data.StructUtils.StructEntry;
     9import org.openstreetmap.josm.data.imagery.DefaultLayer;
     10import org.openstreetmap.josm.data.imagery.Shape;
     11import org.openstreetmap.josm.tools.MultiMap;
     12
     13public class SourcePreferenceEntry<T extends SourceInfo<?, ?, ?, ?>> {
     14    @StructEntry String name;
     15    @StructEntry String d;
     16    @StructEntry String id;
     17    @StructEntry String type;
     18    @StructEntry String url;
     19    @StructEntry double pixel_per_eastnorth;
     20    @StructEntry String eula;
     21    @StructEntry String attribution_text;
     22    @StructEntry String attribution_url;
     23    @StructEntry String permission_reference_url;
     24    @StructEntry String logo_image;
     25    @StructEntry String logo_url;
     26    @StructEntry String terms_of_use_text;
     27    @StructEntry String terms_of_use_url;
     28    @StructEntry String country_code = "";
     29    @StructEntry String date;
     30    @StructEntry int max_zoom;
     31    @StructEntry int min_zoom;
     32    @StructEntry String cookies;
     33    @StructEntry String bounds;
     34    @StructEntry String shapes;
     35    @StructEntry String projections;
     36    @StructEntry String icon;
     37    @StructEntry String description;
     38    @StructEntry MultiMap<String, String> noTileHeaders;
     39    @StructEntry MultiMap<String, String> noTileChecksums;
     40    @StructEntry int tileSize = -1;
     41    @StructEntry Map<String, String> metadataHeaders;
     42    @StructEntry boolean valid_georeference;
     43    @StructEntry boolean bestMarked;
     44    @StructEntry boolean modTileFeatures;
     45    @StructEntry boolean overlay;
     46    @StructEntry String default_layers;
     47    @StructEntry Map<String, String> customHttpHeaders;
     48    @StructEntry boolean transparent;
     49    @StructEntry int minimumTileExpire;
     50    @StructEntry String category;
     51
     52    /**
     53     * Constructs a new empty WMS {@code ImageryPreferenceEntry}.
     54     */
     55    public SourcePreferenceEntry() {
     56        // Do nothing
     57    }
     58
     59    /**
     60     * Constructs a new {@code ImageryPreferenceEntry} from a given {@code ImageryInfo}.
     61     * @param i The corresponding imagery info
     62     */
     63    public SourcePreferenceEntry(T i) {
     64        name = i.name;
     65        id = i.id;
     66        type = i.sourceType.getTypeString();
     67        url = i.url;
     68        pixel_per_eastnorth = i.pixelPerDegree;
     69        eula = i.eulaAcceptanceRequired;
     70        attribution_text = i.attributionText;
     71        attribution_url = i.attributionLinkURL;
     72        permission_reference_url = i.permissionReferenceURL;
     73        date = i.date;
     74        bestMarked = i.bestMarked;
     75        overlay = i.overlay;
     76        logo_image = i.attributionImage;
     77        logo_url = i.attributionImageURL;
     78        terms_of_use_text = i.termsOfUseText;
     79        terms_of_use_url = i.termsOfUseURL;
     80        country_code = i.countryCode;
     81        max_zoom = i.defaultMaxZoom;
     82        min_zoom = i.defaultMinZoom;
     83        cookies = i.cookies;
     84        icon = intern(i.icon);
     85        description = i.description;
     86        category = i.category != null ? i.category.getCategoryString() : null;
     87        if (i.bounds != null) {
     88            bounds = i.bounds.encodeAsString(",");
     89            StringBuilder shapesString = new StringBuilder();
     90            for (Shape s : i.bounds.getShapes()) {
     91                if (shapesString.length() > 0) {
     92                    shapesString.append(';');
     93                }
     94                shapesString.append(s.encodeAsString(","));
     95            }
     96            if (shapesString.length() > 0) {
     97                shapes = shapesString.toString();
     98            }
     99        }
     100        if (!i.serverProjections.isEmpty()) {
     101            projections = String.join(",", i.serverProjections);
     102        }
     103        if (i.noTileHeaders != null && !i.noTileHeaders.isEmpty()) {
     104            noTileHeaders = new MultiMap<>(i.noTileHeaders);
     105        }
     106
     107        if (i.noTileChecksums != null && !i.noTileChecksums.isEmpty()) {
     108            noTileChecksums = new MultiMap<>(i.noTileChecksums);
     109        }
     110
     111        if (i.metadataHeaders != null && !i.metadataHeaders.isEmpty()) {
     112            metadataHeaders = i.metadataHeaders;
     113        }
     114
     115        tileSize = i.getTileSize();
     116
     117        valid_georeference = i.isGeoreferenceValid();
     118        modTileFeatures = i.isModTileFeatures();
     119        if (!i.defaultLayers.isEmpty()) {
     120            default_layers = i.defaultLayers.stream().map(DefaultLayer::toJson).collect(JsonCollectors.toJsonArray()).toString();
     121        }
     122        customHttpHeaders = i.customHttpHeaders;
     123        transparent = i.isTransparent();
     124        minimumTileExpire = i.minimumTileExpire;
     125    }
     126
     127    @Override
     128    public String toString();
     129}
  • src/org/openstreetmap/josm/io/imagery/ImageryReader.java

     
    433433                    entry.addOldId(accumulator.toString());
    434434                    break;
    435435                case "type":
    436                     ImageryType type = ImageryType.fromString(accumulator.toString());
     436                    ImageryType type = ImageryType.getFromString(accumulator.toString());
    437437                    if (type != null)
    438438                        entry.setImageryType(type);
    439439                    else
     
    532532                    break;
    533533                case "category":
    534534                    String cat = accumulator.toString();
    535                     ImageryCategory category = ImageryCategory.fromString(cat);
     535                    ImageryCategory category = ImageryCategory.getFromString(cat);
    536536                    if (category != null)
    537537                        entry.setImageryCategory(category);
    538538                    entry.setImageryCategoryOriginalString(cat);