001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.sources; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.Image; 007import java.util.ArrayList; 008import java.util.Collection; 009import java.util.Collections; 010import java.util.HashMap; 011import java.util.List; 012import java.util.Locale; 013import java.util.Map; 014import java.util.Objects; 015import java.util.Set; 016import java.util.TreeSet; 017import java.util.stream.Collectors; 018 019import javax.swing.ImageIcon; 020 021import org.openstreetmap.gui.jmapviewer.interfaces.Attributed; 022import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; 023import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource; 024import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik; 025import org.openstreetmap.gui.jmapviewer.tilesources.TileSourceInfo; 026import org.openstreetmap.josm.data.StructUtils; 027import org.openstreetmap.josm.data.imagery.DefaultLayer; 028import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry; 029import org.openstreetmap.josm.io.Capabilities; 030import org.openstreetmap.josm.io.OsmApi; 031import org.openstreetmap.josm.spi.preferences.Config; 032import org.openstreetmap.josm.spi.preferences.IPreferences; 033import org.openstreetmap.josm.tools.ImageProvider; 034import org.openstreetmap.josm.tools.LanguageInfo; 035import org.openstreetmap.josm.tools.MultiMap; 036import org.openstreetmap.josm.tools.Utils; 037 038/** 039 * This class is an abstraction for source information to be used in a panel like ImageryProvidersPanel. 040 * 041 * @author Taylor Smock 042 * @param <T> The SourceCategory The categories enum for the source 043 * @param <U> The SourceType The type enum of the source 044 * @param <V> The SourceBounds The bound type for the entry 045 * @param <W> The storage for the entry 046 * 047 * @since 16545 048 */ 049public class SourceInfo<T extends ISourceCategory<?>, U extends ISourceType<?>, V extends SourceBounds, W extends SourcePreferenceEntry<?>> 050 extends TileSourceInfo implements Comparable<SourceInfo<T, U, V, W>>, Attributed { 051 /** original name of the source entry in case of translation call, for multiple languages English when possible */ 052 protected String origName; 053 /** (original) language of the translated name entry */ 054 protected String langName; 055 /** whether this is a entry activated by default or not */ 056 protected boolean defaultEntry; 057 /** Whether this service requires a explicit EULA acceptance before it can be activated */ 058 protected String eulaAcceptanceRequired; 059 /** type of the services - WMS, TMS, ... */ 060 protected U sourceType; 061 /** display bounds of imagery, displayed in prefs and used for automatic imagery selection */ 062 protected V bounds; 063 /** description of the imagery entry, should contain notes what type of data it is */ 064 protected String description; 065 /** language of the description entry */ 066 protected String langDescription; 067 /** Text of a text attribution displayed when using the imagery */ 068 protected String attributionText; 069 /** Link to the privacy policy of the operator */ 070 protected String privacyPolicyURL; 071 /** Link to a reference stating the permission for OSM usage */ 072 protected String permissionReferenceURL; 073 /** Link behind the text attribution displayed when using the imagery */ 074 protected String attributionLinkURL; 075 /** Image of a graphical attribution displayed when using the imagery */ 076 protected String attributionImage; 077 /** Link behind the graphical attribution displayed when using the imagery */ 078 protected String attributionImageURL; 079 /** Text with usage terms displayed when using the imagery */ 080 protected String termsOfUseText; 081 /** Link behind the text with usage terms displayed when using the imagery */ 082 protected String termsOfUseURL; 083 /** country code of the imagery (for country specific imagery) */ 084 protected String countryCode = ""; 085 /** 086 * creation date of the source (in the form YYYY-MM-DD;YYYY-MM-DD, where 087 * DD and MM as well as a second date are optional). 088 * 089 * Also used as time filter for WMS time={time} parameter (such as Sentinel-2) 090 * @since 11570 091 */ 092 protected String date; 093 /** 094 * list of old IDs, only for loading, not handled anywhere else 095 * @since 13536 096 */ 097 protected Collection<String> oldIds; 098 /** icon used in menu */ 099 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, 16545 (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 -> !Utils.isEmpty(prefEntry.id)) 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 (!Utils.isEmpty(dateStr)) { 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 (!Utils.isEmpty(desc)) { 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}