source: josm/trunk/src/org/openstreetmap/josm/data/imagery/ImageryLayerInfo.java@ 8510

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

checkstyle: enable relevant whitespace checks and fix them

  • Property svn:eol-style set to native
File size: 10.7 KB
RevLine 
[3719]1// License: GPL. For details, see LICENSE file.
[3715]2package org.openstreetmap.josm.data.imagery;
3
4import java.io.IOException;
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.Collection;
8import java.util.Collections;
[7186]9import java.util.HashMap;
10import java.util.HashSet;
[3715]11import java.util.List;
[7186]12import java.util.Map;
[7083]13import java.util.Objects;
[7186]14import java.util.Set;
15import java.util.TreeSet;
[7434]16
[3715]17import org.openstreetmap.josm.Main;
[4450]18import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryPreferenceEntry;
[7248]19import org.openstreetmap.josm.io.CachedFile;
[7434]20import org.openstreetmap.josm.io.OfflineAccessException;
21import org.openstreetmap.josm.io.OnlineResource;
[4240]22import org.openstreetmap.josm.io.imagery.ImageryReader;
[6248]23import org.xml.sax.SAXException;
[3715]24
[4450]25/**
26 * Manages the list of imagery entries that are shown in the imagery menu.
27 */
[3715]28public class ImageryLayerInfo {
[3826]29
[3715]30 public static final ImageryLayerInfo instance = new ImageryLayerInfo();
[7186]31 private final List<ImageryInfo> layers = new ArrayList<>();
32 private final Map<String, ImageryInfo> layerIds = new HashMap<>();
[8130]33 private static final List<ImageryInfo> defaultLayers = new ArrayList<>();
34 private static final Map<String, ImageryInfo> defaultLayerIds = new HashMap<>();
[3715]35
[6883]36 private static final String[] DEFAULT_LAYER_SITES = {
[6897]37 Main.getJOSMWebsite()+"/maps"
[3826]38 };
39
[7434]40 /**
41 * Returns the list of imagery layers sites.
42 * @return the list of imagery layers sites
43 * @since 7434
44 */
45 public static Collection<String> getImageryLayersSites() {
46 return Main.pref.getCollection("imagery.layers.sites", Arrays.asList(DEFAULT_LAYER_SITES));
47 }
48
[4016]49 private ImageryLayerInfo() {
50 }
51
52 public ImageryLayerInfo(ImageryLayerInfo info) {
53 layers.addAll(info.layers);
54 }
55
[4216]56 public void clear() {
57 layers.clear();
[7186]58 layerIds.clear();
[4216]59 }
60
[4016]61 public void load() {
[7186]62 clear();
[4450]63 List<ImageryPreferenceEntry> entries = Main.pref.getListOfStructs("imagery.entries", null, ImageryPreferenceEntry.class);
[4881]64 if (entries != null) {
[4450]65 for (ImageryPreferenceEntry prefEntry : entries) {
[4853]66 try {
67 ImageryInfo i = new ImageryInfo(prefEntry);
68 add(i);
69 } catch (IllegalArgumentException e) {
[6248]70 Main.warn("Unable to load imagery preference entry:"+e);
[4853]71 }
[4450]72 }
73 Collections.sort(layers);
74 }
[7186]75 loadDefaults(false);
[4450]76 }
77
[5729]78 /**
79 * Loads the available imagery entries.
80 *
81 * The data is downloaded from the JOSM website (or loaded from cache).
82 * Entries marked as "default" are added to the user selection, if not
83 * already present.
84 *
85 * @param clearCache if true, clear the cache and start a fresh download.
86 */
[4016]87 public void loadDefaults(boolean clearCache) {
88 defaultLayers.clear();
[7186]89 defaultLayerIds.clear();
[7434]90 for (String source : getImageryLayersSites()) {
91 boolean online = true;
92 try {
93 OnlineResource.JOSM_WEBSITE.checkOfflineAccess(source, Main.getJOSMWebsite());
94 } catch (OfflineAccessException e) {
95 Main.warn(e.getMessage());
96 online = false;
97 }
98 if (clearCache && online) {
[7248]99 CachedFile.cleanup(source);
[4240]100 }
101 try {
102 ImageryReader reader = new ImageryReader(source);
103 Collection<ImageryInfo> result = reader.parse();
104 defaultLayers.addAll(result);
105 } catch (IOException ex) {
[6642]106 Main.error(ex, false);
107 } catch (SAXException ex) {
108 Main.error(ex);
[4240]109 }
110 }
[8465]111 while (defaultLayers.remove(null)) {
112 // Do nothing
113 }
[7186]114 Collections.sort(defaultLayers);
115 buildIdMap(defaultLayers, defaultLayerIds);
116 updateEntriesFromDefaults();
117 buildIdMap(layers, layerIds);
118 }
[7434]119
[7186]120 /**
121 * Build the mapping of unique ids to {@link ImageryInfo}s.
122 * @param lst input list
123 * @param idMap output map
124 */
125 private static void buildIdMap(List<ImageryInfo> lst, Map<String, ImageryInfo> idMap) {
126 idMap.clear();
127 Set<String> notUnique = new HashSet<>();
128 for (ImageryInfo i : lst) {
129 if (i.getId() != null) {
130 if (idMap.containsKey(i.getId())) {
131 notUnique.add(i.getId());
132 Main.error("Id ''{0}'' is not unique - used by ''{1}'' and ''{2}''!",
133 i.getId(), i.getName(), idMap.get(i.getId()).getName());
134 continue;
135 }
136 idMap.put(i.getId(), i);
137 }
138 }
139 for (String i : notUnique) {
140 idMap.remove(i);
141 }
142 }
[7434]143
[7186]144 /**
145 * Update user entries according to the list of default entries.
146 */
147 public void updateEntriesFromDefaults() {
148 // add new default entries to the user selection
149 boolean changed = false;
150 Collection<String> knownDefaults = Main.pref.getCollection("imagery.layers.default");
151 Collection<String> newKnownDefaults = new TreeSet<>(knownDefaults);
[4240]152 for (ImageryInfo def : defaultLayers) {
[8344]153 // temporary migration code, so all user preferences will get updated with new settings from JOSM site (can be removed ~Dez. 2015)
[8444]154 if (def.getNoTileHeaders() != null || def.getTileSize() > 0 || def.getMetadataHeaders() != null) {
[8344]155 for (ImageryInfo i: layers) {
156 if (isSimilar(def, i)) {
[8349]157 if (def.getNoTileHeaders() != null) {
158 i.setNoTileHeaders(def.getNoTileHeaders());
159 }
160 if (def.getTileSize() > 0) {
161 i.setTileSize(def.getTileSize());
162 }
[8418]163 if (def.getMetadataHeaders() != null && def.getMetadataHeaders().size() > 0) {
164 i.setMetadataHeaders(def.getMetadataHeaders());
165 }
[8344]166 changed = true;
167 }
168 }
169 }
170
[4240]171 if (def.isDefaultEntry()) {
172 boolean isKnownDefault = false;
[7186]173 for (String url : knownDefaults) {
[4240]174 if (isSimilar(url, def.getUrl())) {
175 isKnownDefault = true;
176 break;
177 }
[3978]178 }
[4240]179 boolean isInUserList = false;
180 if (!isKnownDefault) {
[7186]181 newKnownDefaults.add(def.getUrl());
[4240]182 for (ImageryInfo i : layers) {
[7186]183 if (isSimilar(def, i)) {
[4240]184 isInUserList = true;
185 break;
[3715]186 }
187 }
188 }
[4240]189 if (!isKnownDefault && !isInUserList) {
190 add(new ImageryInfo(def));
[7186]191 changed = true;
[4240]192 }
[3715]193 }
194 }
[7186]195 Main.pref.putCollection("imagery.layers.default", newKnownDefaults);
[3715]196
[7186]197 // Add ids to user entries without id.
198 // Only do this the first time for each id, so the user can have
199 // custom entries that don't get updated automatically
200 Collection<String> addedIds = Main.pref.getCollection("imagery.layers.addedIds");
201 Collection<String> newAddedIds = new TreeSet<>(addedIds);
202 for (ImageryInfo info : layers) {
203 for (ImageryInfo def : defaultLayers) {
204 if (isSimilar(def, info)) {
205 if (def.getId() != null && !addedIds.contains(def.getId())) {
206 if (!defaultLayerIds.containsKey(def.getId())) {
207 // ignore ids used more than once (have been purged from the map)
208 continue;
209 }
210 newAddedIds.add(def.getId());
211 if (info.getId() == null) {
212 info.setId(def.getId());
213 changed = true;
214 }
215 }
216 }
217 }
218 }
[7203]219 Main.pref.putCollection("imagery.layers.addedIds", newAddedIds);
[7434]220
[7186]221 // automatically update user entries with same id as a default entry
[8510]222 for (int i = 0; i < layers.size(); i++) {
[7186]223 ImageryInfo info = layers.get(i);
224 if (info.getId() == null) {
225 continue;
226 }
227 ImageryInfo matchingDefault = defaultLayerIds.get(info.getId());
228 if (matchingDefault != null && !matchingDefault.equalsPref(info)) {
229 layers.set(i, matchingDefault);
230 changed = true;
231 }
232 }
[7434]233
[7186]234 if (changed) {
235 save();
236 }
[3715]237 }
[4428]238
[7186]239 private boolean isSimilar(ImageryInfo iiA, ImageryInfo iiB) {
240 if (iiA.getId() != null && iiB.getId() != null) return iiA.getId().equals(iiB.getId());
241 return isSimilar(iiA.getUrl(), iiB.getUrl());
242 }
[7434]243
[4240]244 // some additional checks to respect extended URLs in preferences (legacy workaround)
245 private boolean isSimilar(String a, String b) {
[7083]246 return Objects.equals(a, b) || (a != null && b != null && !a.isEmpty() && !b.isEmpty() && (a.contains(b) || b.contains(a)));
[4240]247 }
[7434]248
[3715]249 public void add(ImageryInfo info) {
250 layers.add(info);
251 }
252
253 public void remove(ImageryInfo info) {
254 layers.remove(info);
255 }
256
257 public void save() {
[7005]258 List<ImageryPreferenceEntry> entries = new ArrayList<>();
[3715]259 for (ImageryInfo info : layers) {
[4450]260 entries.add(new ImageryPreferenceEntry(info));
[3715]261 }
[4450]262 Main.pref.putListOfStructs("imagery.entries", entries, ImageryPreferenceEntry.class);
[3715]263 }
264
265 public List<ImageryInfo> getLayers() {
266 return Collections.unmodifiableList(layers);
267 }
268
269 public List<ImageryInfo> getDefaultLayers() {
270 return Collections.unmodifiableList(defaultLayers);
271 }
272
273 public static void addLayer(ImageryInfo info) {
274 instance.add(info);
275 instance.save();
276 }
[5369]277
278 public static void addLayers(Collection<ImageryInfo> infos) {
279 for (ImageryInfo i : infos) {
280 instance.add(i);
281 }
282 instance.save();
283 Collections.sort(instance.layers);
284 }
[7434]285
[7186]286 /**
287 * Get unique id for ImageryInfo.
[7434]288 *
[7186]289 * This takes care, that no id is used twice (due to a user error)
290 * @param info the ImageryInfo to look up
291 * @return null, if there is no id or the id is used twice,
292 * the corresponding id otherwise
293 */
294 public String getUniqueId(ImageryInfo info) {
295 if (info.getId() != null && layerIds.get(info.getId()) == info) {
296 return info.getId();
297 }
298 return null;
299 }
[3715]300}
Note: See TracBrowser for help on using the repository browser.