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