001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.imagery; 003 004import java.util.ArrayList; 005import java.util.Collection; 006import java.util.List; 007import java.util.Map; 008import java.util.concurrent.ConcurrentHashMap; 009import java.util.stream.Stream; 010 011import org.openstreetmap.josm.data.Bounds; 012import org.openstreetmap.josm.tools.Utils; 013 014/** 015 * The details of a layer of this WMS server. 016 */ 017public class LayerDetails { 018 private final Map<String, String> styles = new ConcurrentHashMap<>(); // name -> title 019 private final Collection<String> crs = new ArrayList<>(); 020 /** 021 * The layer name (WMS {@code Title}) 022 */ 023 private String title; 024 /** 025 * The layer name (WMS {@code Name}) 026 */ 027 private String name; 028 /** 029 * The layer abstract (WMS {@code Abstract}) 030 * @since 13199 031 */ 032 private String abstr; 033 private final LayerDetails parentLayer; 034 private Bounds bounds; 035 private List<LayerDetails> children = new ArrayList<>(); 036 037 /** 038 * Constructor pointing to parent layer. Set to null if this is topmost layer. 039 * This is needed to properly handle layer attributes inheritance. 040 * 041 * @param parentLayer parent layer 042 */ 043 public LayerDetails(LayerDetails parentLayer) { 044 this.parentLayer = parentLayer; 045 } 046 047 /** 048 * Returns projections that are supported by this layer. 049 * @return projections that are supported by this layer 050 */ 051 public Collection<String> getCrs() { 052 Collection<String> ret = new ArrayList<>(); 053 if (parentLayer != null) { 054 ret.addAll(parentLayer.getCrs()); 055 } 056 ret.addAll(crs); 057 return ret; 058 } 059 060 /** 061 * Returns styles defined for this layer. 062 * @return styles defined for this layer 063 */ 064 public Map<String, String> getStyles() { 065 Map<String, String> ret = new ConcurrentHashMap<>(); 066 if (parentLayer != null) { 067 ret.putAll(parentLayer.getStyles()); 068 } 069 ret.putAll(styles); 070 return ret; 071 } 072 073 /** 074 * Returns "Human readable" title of this layer 075 * @return "Human readable" title of this layer 076 * @see LayerDetails#getName() 077 */ 078 public String getTitle() { 079 return title; 080 } 081 082 /** 083 * Sets title of this layer 084 * @param title title of this layer 085 * @see LayerDetails#getName() 086 */ 087 public void setTitle(String title) { 088 this.title = title; 089 } 090 091 /** 092 * 093 * Citation from OGC WMS specification (WMS 1.3.0):<p><i> 094 * A number of elements have both a {@literal <Name>} and a {@literal <Title>}. The Name is a text string used for machine-to-machine 095 * communication while the Title is for the benefit of humans. For example, a dataset might have the descriptive Title 096 * “Maximum Atmospheric Temperature” and be requested using the abbreviated Name “ATMAX”.</i></p> 097 * 098 * And second citation:<p><i> 099 * If, and only if, a layer has a {@literal <Name>}, then it is a map layer that can be requested by using that Name in the 100 * LAYERS parameter of a GetMap request. A Layer that contains a {@literal <Name>} element is referred to as a “named 101 * layer” in this International Standard. If the layer has a Title but no Name, then that layer is only a category title for 102 * all the layers nested within.</i></p> 103 * @return name of this layer 104 */ 105 public String getName() { 106 return name; 107 } 108 109 /** 110 * Sets the name of this Layer. 111 * @param name the name of this Layer 112 * @see LayerDetails#getName() 113 */ 114 public void setName(String name) { 115 this.name = name; 116 } 117 118 /** 119 * Add style to list of styles defined by this layer 120 * @param name machine-to-machine name of this style 121 * @param title human readable title of this style 122 */ 123 public void addStyle(String name, String title) { 124 this.styles.put(name, title == null ? "" : title); 125 } 126 127 /** 128 * Add projection supported by this layer 129 * @param crs projection code 130 */ 131 public void addCrs(String crs) { 132 this.crs.add(crs); 133 } 134 135 /** 136 * Returns bounds within layer might be queried. 137 * @return bounds within layer might be queried 138 */ 139 public Bounds getBounds() { 140 return bounds; 141 } 142 143 /** 144 * Sets bounds of this layer 145 * @param bounds of this layer 146 */ 147 public void setBounds(Bounds bounds) { 148 this.bounds = bounds; 149 } 150 151 @Override 152 public String toString() { 153 String baseName = Utils.isEmpty(title) ? name : title; 154 return abstr == null || abstr.equalsIgnoreCase(baseName) ? baseName : baseName + " (" + abstr + ')'; 155 } 156 157 /** 158 * Returns parent layer for this layer. 159 * @return parent layer for this layer 160 */ 161 public LayerDetails getParent() { 162 return parentLayer; 163 } 164 165 /** 166 * sets children layers for this layer 167 * @param children children of this layer 168 */ 169 public void setChildren(List<LayerDetails> children) { 170 this.children = children; 171 172 } 173 174 /** 175 * Returns children layers of this layer. 176 * @return children layers of this layer 177 */ 178 public List<LayerDetails> getChildren() { 179 return children; 180 } 181 182 /** 183 * if user may select this layer (is it possible to request it from server) 184 * @return true if user may select this layer, false if this layer is only grouping other layers 185 */ 186 public boolean isSelectable() { 187 return !Utils.isEmpty(name); 188 } 189 190 /** 191 * Returns abstract of this layer. 192 * @return "Narrative description of the layer" 193 */ 194 public String getAbstract() { 195 return abstr; 196 } 197 198 /** 199 * Sets abstract of this layer 200 * @param abstr abstract of this layer 201 */ 202 public void setAbstract(String abstr) { 203 this.abstr = abstr; 204 } 205 206 /** 207 * Returns flattened stream of this layer and its children. 208 * @return flattened stream of this layer and its children (as well as recursively children of its children) 209 */ 210 public Stream<LayerDetails> flattened() { 211 return Stream.concat( 212 Stream.of(this), 213 getChildren().stream().flatMap(LayerDetails::flattened) 214 ); 215 } 216}