source: josm/trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java@ 4856

Last change on this file since 4856 was 4856, checked in by stoecker, 12 years ago

fix typo

  • Property svn:eol-style set to native
File size: 19.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.imagery;
3
4import java.awt.Image;
5import java.util.Arrays;
6import java.util.ArrayList;
7import java.util.Collection;
8import java.util.Collections;
9import java.util.List;
10import java.util.regex.Matcher;
11import java.util.regex.Pattern;
12
13import javax.swing.ImageIcon;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.data.Bounds;
17import org.openstreetmap.josm.data.Preferences.pref;
18import org.openstreetmap.josm.io.OsmApi;
19import org.openstreetmap.josm.tools.CheckParameterUtil;
20import org.openstreetmap.josm.tools.ImageProvider;
21import org.openstreetmap.gui.jmapviewer.Coordinate;
22import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
23import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource.Mapnik;
24import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTileSource;
25import org.openstreetmap.josm.tools.CheckParameterUtil;
26
27/**
28 * Class that stores info about an image background layer.
29 *
30 * @author Frederik Ramm <frederik@remote.org>
31 */
32public class ImageryInfo implements Comparable<ImageryInfo>, Attributed {
33
34 public enum ImageryType {
35 WMS("wms"),
36 TMS("tms"),
37 HTML("html"),
38 BING("bing"),
39 SCANEX("scanex");
40
41 private String urlString;
42 ImageryType(String urlString) {
43 this.urlString = urlString;
44 }
45 public String getUrlString() {
46 return urlString;
47 }
48 }
49
50 public static class ImageryBounds extends Bounds {
51 public ImageryBounds(String asString, String separator) {
52 super(asString, separator);
53 }
54
55 private List<Shape> shapes = new ArrayList<Shape>();
56
57 public void addShape(Shape shape) {
58 this.shapes.add(shape);
59 }
60
61 public void setShapes(List<Shape> shapes) {
62 this.shapes = shapes;
63 }
64
65 public List<Shape> getShapes() {
66 return shapes;
67 }
68 }
69
70 private String name;
71 private String url = null;
72 private boolean defaultEntry = false;
73 private String cookies = null;
74 private String eulaAcceptanceRequired= null;
75 private ImageryType imageryType = ImageryType.WMS;
76 private double pixelPerDegree = 0.0;
77 private int defaultMaxZoom = 0;
78 private int defaultMinZoom = 0;
79 private ImageryBounds bounds = null;
80 private List<String> serverProjections;
81 private String attributionText;
82 private String attributionLinkURL;
83 private String attributionImage;
84 private String attributionImageURL;
85 private String termsOfUseText;
86 private String termsOfUseURL;
87 private String countryCode = "";
88 private String icon;
89
90 /** auxiliary class to save an ImageryInfo object in the preferences */
91 public static class ImageryPreferenceEntry {
92 @pref String name;
93 @pref String type;
94 @pref String url;
95 @pref double pixel_per_eastnorth;
96 @pref String eula;
97 @pref String attribution_text;
98 @pref String attribution_url;
99 @pref String logo_image;
100 @pref String logo_url;
101 @pref String terms_of_use_text;
102 @pref String terms_of_use_url;
103 @pref String country_code = "";
104 @pref int max_zoom;
105 @pref int min_zoom;
106 @pref String cookies;
107 @pref String bounds;
108 @pref String shapes;
109 @pref String projections;
110 @pref String icon;
111
112 public ImageryPreferenceEntry() {
113 }
114
115 public ImageryPreferenceEntry(ImageryInfo i) {
116 name = i.name;
117 type = i.imageryType.getUrlString();
118 url = i.url;
119 pixel_per_eastnorth = i.pixelPerDegree;
120 eula = i.eulaAcceptanceRequired;
121 attribution_text = i.attributionText;
122 attribution_url = i.attributionLinkURL;
123 logo_image = i.attributionImage;
124 logo_url = i.attributionImageURL;
125 terms_of_use_text = i.termsOfUseText;
126 terms_of_use_url = i.termsOfUseURL;
127 country_code = i.countryCode;
128 max_zoom = i.defaultMaxZoom;
129 min_zoom = i.defaultMinZoom;
130 cookies = i.cookies;
131 icon = i.icon;
132 if (i.bounds != null) {
133 bounds = i.bounds.encodeAsString(",");
134 String shapesString = "";
135 for (Shape s : i.bounds.getShapes()) {
136 if (!shapesString.isEmpty()) {
137 shapesString += ";";
138 }
139 shapesString += s.encodeAsString(",");
140 }
141 if (!shapesString.isEmpty()) {
142 shapes = shapesString;
143 }
144 }
145 if (i.serverProjections != null && !i.serverProjections.isEmpty()) {
146 String val = "";
147 for (String p : i.serverProjections) {
148 if (!val.isEmpty())
149 val += ",";
150 val += p;
151 }
152 projections = val;
153 }
154 }
155 }
156
157 public ImageryInfo() {
158 }
159
160 public ImageryInfo(String name) {
161 this.name=name;
162 }
163
164 public ImageryInfo(String name, String url) {
165 this.name=name;
166 setExtendedUrl(url);
167 }
168
169 public ImageryInfo(String name, String url, String eulaAcceptanceRequired) {
170 this.name=name;
171 setExtendedUrl(url);
172 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
173 }
174
175 public ImageryInfo(String name, String url, String eulaAcceptanceRequired, String cookies) {
176 this.name=name;
177 setExtendedUrl(url);
178 this.cookies=cookies;
179 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
180 }
181
182 public ImageryInfo(String name, String url, String cookies, double pixelPerDegree) {
183 this.name=name;
184 setExtendedUrl(url);
185 this.cookies=cookies;
186 this.pixelPerDegree=pixelPerDegree;
187 }
188
189 public ImageryInfo(ImageryPreferenceEntry e) {
190 CheckParameterUtil.ensureParameterNotNull(e.name, "name");
191 CheckParameterUtil.ensureParameterNotNull(e.url, "url");
192 name = e.name;
193 url = e.url;
194 cookies = e.cookies;
195 eulaAcceptanceRequired = e.eula;
196 for (ImageryType type : ImageryType.values()) {
197 if (type.getUrlString().equals(e.type)) {
198 imageryType = type;
199 break;
200 }
201 }
202 if (imageryType == null) throw new IllegalArgumentException("unknown type");
203 pixelPerDegree = e.pixel_per_eastnorth;
204 defaultMaxZoom = e.max_zoom;
205 defaultMinZoom = e.min_zoom;
206 if (e.bounds != null) {
207 bounds = new ImageryBounds(e.bounds, ",");
208 if (e.shapes != null) {
209 try {
210 for (String s : e.shapes.split(";")) {
211 bounds.addShape(new Shape(s, ","));
212 }
213 } catch (IllegalArgumentException ex) {
214 Main.warn(ex.toString());
215 }
216 }
217 }
218 if (e.projections != null) {
219 serverProjections = Arrays.asList(e.projections.split(","));
220 }
221 attributionText = e.attribution_text;
222 attributionLinkURL = e.attribution_url;
223 attributionImage = e.logo_image;
224 attributionImageURL = e.logo_url;
225 termsOfUseText = e.terms_of_use_text;
226 termsOfUseURL = e.terms_of_use_url;
227 countryCode = e.country_code;
228 icon = e.icon;
229 }
230
231 public ImageryInfo(Collection<String> list) {
232 ArrayList<String> array = new ArrayList<String>(list);
233 this.name=array.get(0);
234 if(array.size() >= 2 && !array.get(1).isEmpty()) {
235 setExtendedUrl(array.get(1));
236 }
237 if(array.size() >= 3 && !array.get(2).isEmpty()) {
238 this.cookies=array.get(2);
239 }
240 if(array.size() >= 4 && !array.get(3).isEmpty()) {
241 if (imageryType == ImageryType.WMS || imageryType == ImageryType.HTML) {
242 this.pixelPerDegree=Double.valueOf(array.get(3));
243 }
244 }
245 if(array.size() >= 5 && !array.get(4).isEmpty()) {
246 try {
247 bounds = new ImageryBounds(array.get(4), ",");
248 } catch (IllegalArgumentException e) {
249 Main.warn(e.toString());
250 }
251 }
252 if(array.size() >= 6 && !array.get(5).isEmpty()) {
253 setAttributionText(array.get(5));
254 }
255 if(array.size() >= 7 && !array.get(6).isEmpty()) {
256 setAttributionLinkURL(array.get(6));
257 }
258 if(array.size() >= 8 && !array.get(7).isEmpty()) {
259 setAttributionImage(array.get(7));
260 }
261 if(array.size() >= 9 && !array.get(8).isEmpty()) {
262 setTermsOfUseURL(array.get(8));
263 }
264 if(bounds != null && array.size() >= 10 && !array.get(9).isEmpty()) {
265 try {
266 for (String s : array.get(9).split(";")) {
267 bounds.addShape(new Shape(s, ","));
268 }
269 } catch (IllegalArgumentException e) {
270 Main.warn(e.toString());
271 }
272 }
273 if(array.size() >= 11 && !array.get(10).isEmpty()) {
274 serverProjections = Arrays.asList(array.get(10).split(","));
275 }
276 }
277
278 public ImageryInfo(ImageryInfo i) {
279 this.name=i.name;
280 this.url=i.url;
281 this.cookies=i.cookies;
282 this.imageryType=i.imageryType;
283 this.defaultMinZoom=i.defaultMinZoom;
284 this.defaultMaxZoom=i.defaultMaxZoom;
285 this.pixelPerDegree=i.pixelPerDegree;
286 this.eulaAcceptanceRequired = null;
287 this.bounds = i.bounds;
288 this.attributionText = i.attributionText;
289 this.attributionLinkURL = i.attributionLinkURL;
290 this.attributionImage = i.attributionImage;
291 this.attributionImageURL = i.attributionImageURL;
292 this.termsOfUseText = i.termsOfUseText;
293 this.termsOfUseURL = i.termsOfUseURL;
294 this.serverProjections = i.serverProjections;
295 this.icon = i.icon;
296 }
297
298 @Override
299 public int compareTo(ImageryInfo in)
300 {
301 int i = countryCode.compareTo(in.countryCode);
302 if (i == 0) {
303 i = name.compareTo(in.name);
304 }
305 if (i == 0) {
306 i = url.compareTo(in.url);
307 }
308 if (i == 0) {
309 i = Double.compare(pixelPerDegree, in.pixelPerDegree);
310 }
311 return i;
312 }
313
314 public boolean equalsBaseValues(ImageryInfo in)
315 {
316 return url.equals(in.url);
317 }
318
319 public void setPixelPerDegree(double ppd) {
320 this.pixelPerDegree = ppd;
321 }
322
323 public void setDefaultMaxZoom(int defaultMaxZoom) {
324 this.defaultMaxZoom = defaultMaxZoom;
325 }
326
327 public void setDefaultMinZoom(int defaultMinZoom) {
328 this.defaultMinZoom = defaultMinZoom;
329 }
330
331 public void setBounds(ImageryBounds b) {
332 this.bounds = b;
333 }
334
335 public ImageryBounds getBounds() {
336 return bounds;
337 }
338
339 @Override
340 public boolean requiresAttribution() {
341 return attributionText != null || attributionImage != null || termsOfUseText != null || termsOfUseURL != null;
342 }
343
344 @Override
345 public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
346 return attributionText;
347 }
348
349 @Override
350 public String getAttributionLinkURL() {
351 return attributionLinkURL;
352 }
353
354 @Override
355 public Image getAttributionImage() {
356 ImageIcon i = ImageProvider.getIfAvailable(attributionImage);
357 if (i != null) {
358 return i.getImage();
359 }
360 return null;
361 }
362
363 @Override
364 public String getAttributionImageURL() {
365 return attributionImageURL;
366 }
367
368 @Override
369 public String getTermsOfUseText() {
370 return termsOfUseText;
371 }
372
373 @Override
374 public String getTermsOfUseURL() {
375 return termsOfUseURL;
376 }
377
378 public void setAttributionText(String text) {
379 attributionText = text;
380 }
381
382 public void setAttributionImageURL(String text) {
383 attributionImageURL = text;
384 }
385
386 public void setAttributionImage(String text) {
387 attributionImage = text;
388 }
389
390 public void setAttributionLinkURL(String text) {
391 attributionLinkURL = text;
392 }
393
394 public void setTermsOfUseText(String text) {
395 termsOfUseText = text;
396 }
397
398 public void setTermsOfUseURL(String text) {
399 termsOfUseURL = text;
400 }
401
402 public void setExtendedUrl(String url) {
403 CheckParameterUtil.ensureParameterNotNull(url);
404
405 // Default imagery type is WMS
406 this.url = url;
407 this.imageryType = ImageryType.WMS;
408
409 defaultMaxZoom = 0;
410 defaultMinZoom = 0;
411 for (ImageryType type : ImageryType.values()) {
412 Matcher m = Pattern.compile(type.getUrlString()+"(?:\\[(?:(\\d+),)?(\\d+)\\])?:(.*)").matcher(url);
413 if(m.matches()) {
414 this.url = m.group(3);
415 this.imageryType = type;
416 if(m.group(2) != null) {
417 defaultMaxZoom = Integer.valueOf(m.group(2));
418 }
419 if(m.group(1) != null) {
420 defaultMinZoom = Integer.valueOf(m.group(1));
421 }
422 break;
423 }
424 }
425
426 if(url.contains("{") && url.contains("}")) {
427 if(serverProjections == null || serverProjections.isEmpty()) {
428 try {
429 serverProjections = new ArrayList<String>();
430 Matcher m = Pattern.compile(".*\\{PROJ\\(([^)}]+)\\)\\}.*").matcher(url.toUpperCase());
431 if(m.matches()) {
432 for(String p : m.group(1).split(","))
433 serverProjections.add(p);
434 }
435 } catch(Exception e) {
436 }
437 }
438 // FIXME: Remove else case in March 2012 - convert old style WMS/TMS
439 } else {
440 url = this.url;
441 if(imageryType == ImageryType.WMS) {
442 if(!url.endsWith("&") && !url.endsWith("?")) {
443 url = url + (url.contains("?") ? "&" : "?");
444 }
445 try {
446 Matcher m = Pattern.compile(".*SRS=([a-z0-9:]+).*", Pattern.CASE_INSENSITIVE).matcher(url.toUpperCase());
447 if(m.matches()) {
448 String newProj = m.group(1);
449 if(serverProjections == null || serverProjections.isEmpty())
450 serverProjections = Collections.singletonList(newProj);
451 url = url.replaceAll("([sS][rR][sS]=)[a-zA-Z0-9:]+","SRS={proj("+newProj+")}");
452 } else
453 url += "SRS={proj}&";
454 } catch(Exception e) {
455 }
456 url += "WIDTH={width}&height={height}&BBOX={bbox}";
457 }
458 else if(imageryType == ImageryType.TMS) {
459 if(!url.endsWith("/"))
460 url += "/";
461 url += "{zoom}/{x}/{y}.png";
462 }
463 if(!url.equals(this.url)) {
464 Main.warn("Changed Imagery URL '"+this.url+"' to '"+url+"'");
465 this.url = url;
466 }
467 }
468 }
469
470 public String getName() {
471 return this.name;
472 }
473
474 public void setName(String name) {
475 this.name = name;
476 }
477
478 public String getUrl() {
479 return this.url;
480 }
481
482 public void setUrl(String url) {
483 this.url = url;
484 }
485
486 public boolean isDefaultEntry() {
487 return defaultEntry;
488 }
489
490 public void setDefaultEntry(boolean defaultEntry) {
491 this.defaultEntry = defaultEntry;
492 }
493
494 public String getCookies() {
495 return this.cookies;
496 }
497
498 public double getPixelPerDegree() {
499 return this.pixelPerDegree;
500 }
501
502 public int getMaxZoom() {
503 return this.defaultMaxZoom;
504 }
505
506 public int getMinZoom() {
507 return this.defaultMinZoom;
508 }
509
510 public String getEulaAcceptanceRequired() {
511 return eulaAcceptanceRequired;
512 }
513
514 public void setEulaAcceptanceRequired(String eulaAcceptanceRequired) {
515 this.eulaAcceptanceRequired = eulaAcceptanceRequired;
516 }
517
518 public String getCountryCode() {
519 return countryCode;
520 }
521
522 public void setCountryCode(String countryCode) {
523 this.countryCode = countryCode;
524 }
525
526 public String getIcon() {
527 return icon;
528 }
529
530 public void setIcon(String icon) {
531 this.icon = icon;
532 }
533
534 /**
535 * Get the projections supported by the server. Only relevant for
536 * WMS-type ImageryInfo at the moment.
537 * @return null, if no projections have been specified; the list
538 * of supported projections otherwise.
539 */
540 public List<String> getServerProjections() {
541 if (serverProjections == null)
542 return Collections.emptyList();
543 return Collections.unmodifiableList(serverProjections);
544 }
545
546 public void setServerProjections(Collection<String> serverProjections) {
547 this.serverProjections = new ArrayList<String>(serverProjections);
548 }
549
550 public String getExtendedUrl() {
551 return imageryType.getUrlString() + (defaultMaxZoom != 0
552 ? "["+(defaultMinZoom != 0 ? defaultMinZoom+",":"")+defaultMaxZoom+"]" : "") + ":" + url;
553 }
554
555 public String getToolbarName()
556 {
557 String res = name;
558 if(pixelPerDegree != 0.0) {
559 res += "#PPD="+pixelPerDegree;
560 }
561 return res;
562 }
563
564 public String getMenuName()
565 {
566 String res = name;
567 if(pixelPerDegree != 0.0) {
568 res += " ("+pixelPerDegree+")";
569 }
570 return res;
571 }
572
573 public boolean hasAttribution()
574 {
575 return attributionText != null;
576 }
577
578 public void copyAttribution(ImageryInfo i)
579 {
580 this.attributionImage = i.attributionImage;
581 this.attributionImageURL = i.attributionImageURL;
582 this.attributionText = i.attributionText;
583 this.attributionLinkURL = i.attributionLinkURL;
584 this.termsOfUseText = i.termsOfUseText;
585 this.termsOfUseURL = i.termsOfUseURL;
586 }
587
588 /**
589 * Applies the attribution from this object to a TMSTileSource.
590 */
591 public void setAttribution(AbstractTileSource s) {
592 if (attributionText != null) {
593 if (attributionText.equals("osm")) {
594 s.setAttributionText(new Mapnik().getAttributionText(0, null, null));
595 } else {
596 s.setAttributionText(attributionText);
597 }
598 }
599 if (attributionLinkURL != null) {
600 if (attributionLinkURL.equals("osm")) {
601 s.setAttributionLinkURL(new Mapnik().getAttributionLinkURL());
602 } else {
603 s.setAttributionLinkURL(attributionLinkURL);
604 }
605 }
606 if (attributionImage != null) {
607 ImageIcon i = ImageProvider.getIfAvailable(null, attributionImage);
608 if (i != null) {
609 s.setAttributionImage(i.getImage());
610 }
611 }
612 if (attributionImageURL != null) {
613 s.setAttributionImageURL(attributionImageURL);
614 }
615 if (termsOfUseText != null) {
616 s.setTermsOfUseText(termsOfUseText);
617 }
618 if (termsOfUseURL != null) {
619 if (termsOfUseURL.equals("osm")) {
620 s.setTermsOfUseURL(new Mapnik().getTermsOfUseURL());
621 } else {
622 s.setTermsOfUseURL(termsOfUseURL);
623 }
624 }
625 }
626
627 public ImageryType getImageryType() {
628 return imageryType;
629 }
630
631 public void setImageryType(ImageryType imageryType) {
632 this.imageryType = imageryType;
633 }
634
635 /**
636 * Returns true if this layer's URL is matched by one of the regular
637 * expressions kept by the current OsmApi instance.
638 */
639 public boolean isBlacklisted() {
640 return OsmApi.getOsmApi().getCapabilities().isOnImageryBlacklist(this.url);
641 }
642}
Note: See TracBrowser for help on using the repository browser.