source: josm/trunk/src/org/openstreetmap/josm/gui/bbox/SlippyMapBBoxChooser.java@ 8285

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

fix sonar squid:S2039 - Member variable visibility should be specified

  • Property svn:eol-style set to native
File size: 13.2 KB
Line 
1// License: GPL. See LICENSE file for details.
2package org.openstreetmap.josm.gui.bbox;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Dimension;
8import java.awt.Graphics;
9import java.awt.Point;
10import java.awt.Rectangle;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.Collections;
14import java.util.HashMap;
15import java.util.HashSet;
16import java.util.List;
17import java.util.Map;
18import java.util.Set;
19import java.util.concurrent.CopyOnWriteArrayList;
20
21import javax.swing.JOptionPane;
22import javax.swing.SpringLayout;
23
24import org.openstreetmap.gui.jmapviewer.Coordinate;
25import org.openstreetmap.gui.jmapviewer.JMapViewer;
26import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
27import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
28import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
29import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
30import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
31import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
32import org.openstreetmap.gui.jmapviewer.tilesources.MapQuestOpenAerialTileSource;
33import org.openstreetmap.gui.jmapviewer.tilesources.MapQuestOsmTileSource;
34import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
35import org.openstreetmap.josm.Main;
36import org.openstreetmap.josm.data.Bounds;
37import org.openstreetmap.josm.data.Version;
38import org.openstreetmap.josm.data.coor.LatLon;
39import org.openstreetmap.josm.data.imagery.ImageryInfo;
40import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
41import org.openstreetmap.josm.data.preferences.StringProperty;
42import org.openstreetmap.josm.gui.layer.TMSLayer;
43
44public class SlippyMapBBoxChooser extends JMapViewer implements BBoxChooser {
45
46 public interface TileSourceProvider {
47 List<TileSource> getTileSources();
48 }
49
50 /**
51 * TMS TileSource provider for the slippymap chooser
52 */
53 public static class TMSTileSourceProvider implements TileSourceProvider {
54 private static final Set<String> existingSlippyMapUrls = new HashSet<>();
55 static {
56 // Urls that already exist in the slippymap chooser and shouldn't be copied from TMS layer list
57 existingSlippyMapUrls.add("https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png"); // Mapnik
58 existingSlippyMapUrls.add("http://tile.opencyclemap.org/cycle/{zoom}/{x}/{y}.png"); // Cyclemap
59 existingSlippyMapUrls.add("http://otile{switch:1,2,3,4}.mqcdn.com/tiles/1.0.0/osm/{zoom}/{x}/{y}.png"); // MapQuest-OSM
60 existingSlippyMapUrls.add("http://oatile{switch:1,2,3,4}.mqcdn.com/tiles/1.0.0/sat/{zoom}/{x}/{y}.png"); // MapQuest Open Aerial
61 }
62
63 @Override
64 public List<TileSource> getTileSources() {
65 if (!TMSLayer.PROP_ADD_TO_SLIPPYMAP_CHOOSER.get()) return Collections.<TileSource>emptyList();
66 List<TileSource> sources = new ArrayList<>();
67 for (ImageryInfo info : ImageryLayerInfo.instance.getLayers()) {
68 if (existingSlippyMapUrls.contains(info.getUrl())) {
69 continue;
70 }
71 try {
72 TileSource source = TMSLayer.getTileSource(info);
73 if (source != null) {
74 sources.add(source);
75 }
76 } catch (IllegalArgumentException ex) {
77 if (ex.getMessage() != null && !ex.getMessage().isEmpty()) {
78 JOptionPane.showMessageDialog(Main.parent,
79 ex.getMessage(), tr("Warning"),
80 JOptionPane.WARNING_MESSAGE);
81 }
82 }
83 }
84 return sources;
85 }
86
87 public static void addExistingSlippyMapUrl(String url) {
88 existingSlippyMapUrls.add(url);
89 }
90 }
91
92 /**
93 * Plugins that wish to add custom tile sources to slippy map choose should call this method
94 * @param tileSourceProvider
95 */
96 public static void addTileSourceProvider(TileSourceProvider tileSourceProvider) {
97 providers.addIfAbsent(tileSourceProvider);
98 }
99
100 private static CopyOnWriteArrayList<TileSourceProvider> providers = new CopyOnWriteArrayList<>();
101
102 static {
103 addTileSourceProvider(new TileSourceProvider() {
104 @Override
105 public List<TileSource> getTileSources() {
106 return Arrays.<TileSource>asList(
107 new OsmTileSource.Mapnik(),
108 new OsmTileSource.CycleMap(),
109 new MapQuestOsmTileSource(),
110 new MapQuestOpenAerialTileSource());
111 }
112 });
113 addTileSourceProvider(new TMSTileSourceProvider());
114 }
115
116 private static final StringProperty PROP_MAPSTYLE = new StringProperty("slippy_map_chooser.mapstyle", "Mapnik");
117 public static final String RESIZE_PROP = SlippyMapBBoxChooser.class.getName() + ".resize";
118
119 private TileLoader cachedLoader;
120 private OsmTileLoader uncachedLoader;
121
122 private final SizeButton iSizeButton;
123 private final SourceButton iSourceButton;
124 private Bounds bbox;
125
126 // upper left and lower right corners of the selection rectangle (x/y on ZOOM_MAX)
127 private Point iSelectionRectStart;
128 private Point iSelectionRectEnd;
129
130 /**
131 * Constructs a new {@code SlippyMapBBoxChooser}.
132 */
133 public SlippyMapBBoxChooser() {
134 debug = Main.isDebugEnabled();
135 SpringLayout springLayout = new SpringLayout();
136 setLayout(springLayout);
137
138 Map<String, String> headers = new HashMap<>();
139 headers.put("User-Agent", Version.getInstance().getFullAgentString());
140
141 cachedLoader = TMSLayer.loaderFactory.makeTileLoader(this, headers);
142
143 uncachedLoader = new OsmTileLoader(this);
144 uncachedLoader.headers.putAll(headers);
145 setZoomContolsVisible(Main.pref.getBoolean("slippy_map_chooser.zoomcontrols",false));
146 setMapMarkerVisible(false);
147 setMinimumSize(new Dimension(350, 350 / 2));
148 // We need to set an initial size - this prevents a wrong zoom selection
149 // for the area before the component has been displayed the first time
150 setBounds(new Rectangle(getMinimumSize()));
151 if (cachedLoader == null) {
152 setFileCacheEnabled(false);
153 } else {
154 setFileCacheEnabled(Main.pref.getBoolean("slippy_map_chooser.file_cache", true));
155 }
156 setMaxTilesInMemory(Main.pref.getInteger("slippy_map_chooser.max_tiles", 1000));
157
158 List<TileSource> tileSources = getAllTileSources();
159
160 iSourceButton = new SourceButton(this, tileSources);
161 add(iSourceButton);
162 springLayout.putConstraint(SpringLayout.EAST, iSourceButton, 0, SpringLayout.EAST, this);
163 springLayout.putConstraint(SpringLayout.NORTH, iSourceButton, 30, SpringLayout.NORTH, this);
164
165 iSizeButton = new SizeButton(this);
166 add(iSizeButton);
167
168 String mapStyle = PROP_MAPSTYLE.get();
169 boolean foundSource = false;
170 for (TileSource source: tileSources) {
171 if (source.getName().equals(mapStyle)) {
172 this.setTileSource(source);
173 iSourceButton.setCurrentMap(source);
174 foundSource = true;
175 break;
176 }
177 }
178 if (!foundSource) {
179 setTileSource(tileSources.get(0));
180 iSourceButton.setCurrentMap(tileSources.get(0));
181 }
182
183 new SlippyMapControler(this, this);
184 }
185
186 private List<TileSource> getAllTileSources() {
187 List<TileSource> tileSources = new ArrayList<>();
188 for (TileSourceProvider provider: providers) {
189 tileSources.addAll(provider.getTileSources());
190 }
191 return tileSources;
192 }
193
194 public boolean handleAttribution(Point p, boolean click) {
195 return attribution.handleAttribution(p, click);
196 }
197
198 protected Point getTopLeftCoordinates() {
199 return new Point(center.x - (getWidth() / 2), center.y - (getHeight() / 2));
200 }
201
202 /**
203 * Draw the map.
204 */
205 @Override
206 public void paint(Graphics g) {
207 try {
208 super.paint(g);
209
210 // draw selection rectangle
211 if (iSelectionRectStart != null && iSelectionRectEnd != null) {
212
213 int zoomDiff = MAX_ZOOM - zoom;
214 Point tlc = getTopLeftCoordinates();
215 int x_min = (iSelectionRectStart.x >> zoomDiff) - tlc.x;
216 int y_min = (iSelectionRectStart.y >> zoomDiff) - tlc.y;
217 int x_max = (iSelectionRectEnd.x >> zoomDiff) - tlc.x;
218 int y_max = (iSelectionRectEnd.y >> zoomDiff) - tlc.y;
219
220 int w = x_max - x_min;
221 int h = y_max - y_min;
222 g.setColor(new Color(0.9f, 0.7f, 0.7f, 0.6f));
223 g.fillRect(x_min, y_min, w, h);
224
225 g.setColor(Color.BLACK);
226 g.drawRect(x_min, y_min, w, h);
227 }
228 } catch (Exception e) {
229 Main.error(e);
230 }
231 }
232
233 public final void setFileCacheEnabled(boolean enabled) {
234 if (enabled) {
235 setTileLoader(cachedLoader);
236 } else {
237 setTileLoader(uncachedLoader);
238 }
239 }
240
241 public final void setMaxTilesInMemory(int tiles) {
242 ((MemoryTileCache) getTileCache()).setCacheSize(tiles);
243 }
244
245 /**
246 * Callback for the OsmMapControl. (Re-)Sets the start and end point of the
247 * selection rectangle.
248 *
249 * @param aStart
250 * @param aEnd
251 */
252 public void setSelection(Point aStart, Point aEnd) {
253 if (aStart == null || aEnd == null || aStart.x == aEnd.x || aStart.y == aEnd.y)
254 return;
255
256 Point p_max = new Point(Math.max(aEnd.x, aStart.x), Math.max(aEnd.y, aStart.y));
257 Point p_min = new Point(Math.min(aEnd.x, aStart.x), Math.min(aEnd.y, aStart.y));
258
259 Point tlc = getTopLeftCoordinates();
260 int zoomDiff = MAX_ZOOM - zoom;
261 Point pEnd = new Point(p_max.x + tlc.x, p_max.y + tlc.y);
262 Point pStart = new Point(p_min.x + tlc.x, p_min.y + tlc.y);
263
264 pEnd.x <<= zoomDiff;
265 pEnd.y <<= zoomDiff;
266 pStart.x <<= zoomDiff;
267 pStart.y <<= zoomDiff;
268
269 iSelectionRectStart = pStart;
270 iSelectionRectEnd = pEnd;
271
272 Coordinate l1 = getPosition(p_max); // lon may be outside [-180,180]
273 Coordinate l2 = getPosition(p_min); // lon may be outside [-180,180]
274 Bounds b = new Bounds(
275 new LatLon(
276 Math.min(l2.getLat(), l1.getLat()),
277 LatLon.toIntervalLon(Math.min(l1.getLon(), l2.getLon()))
278 ),
279 new LatLon(
280 Math.max(l2.getLat(), l1.getLat()),
281 LatLon.toIntervalLon(Math.max(l1.getLon(), l2.getLon())))
282 );
283 Bounds oldValue = this.bbox;
284 this.bbox = b;
285 repaint();
286 firePropertyChange(BBOX_PROP, oldValue, this.bbox);
287 }
288
289 /**
290 * Performs resizing of the DownloadDialog in order to enlarge or shrink the
291 * map.
292 */
293 public void resizeSlippyMap() {
294 boolean large = iSizeButton.isEnlarged();
295 firePropertyChange(RESIZE_PROP, !large, large);
296 }
297
298 public void toggleMapSource(TileSource tileSource) {
299 this.tileController.setTileCache(new MemoryTileCache());
300 this.setTileSource(tileSource);
301 PROP_MAPSTYLE.put(tileSource.getName()); // TODO Is name really unique?
302 }
303
304 @Override
305 public Bounds getBoundingBox() {
306 return bbox;
307 }
308
309 /**
310 * Sets the current bounding box in this bbox chooser without
311 * emiting a property change event.
312 *
313 * @param bbox the bounding box. null to reset the bounding box
314 */
315 @Override
316 public void setBoundingBox(Bounds bbox) {
317 if (bbox == null || (bbox.getMinLat() == 0.0 && bbox.getMinLon() == 0.0
318 && bbox.getMaxLat() == 0.0 && bbox.getMaxLon() == 0.0)) {
319 this.bbox = null;
320 iSelectionRectStart = null;
321 iSelectionRectEnd = null;
322 repaint();
323 return;
324 }
325
326 this.bbox = bbox;
327 double minLon = bbox.getMinLon();
328 double maxLon = bbox.getMaxLon();
329
330 if (bbox.crosses180thMeridian()) {
331 minLon -= 360.0;
332 }
333
334 int y1 = tileSource.LatToY(bbox.getMinLat(), MAX_ZOOM);
335 int y2 = tileSource.LatToY(bbox.getMaxLat(), MAX_ZOOM);
336 int x1 = tileSource.LonToX(minLon, MAX_ZOOM);
337 int x2 = tileSource.LonToX(maxLon, MAX_ZOOM);
338
339 iSelectionRectStart = new Point(Math.min(x1, x2), Math.min(y1, y2));
340 iSelectionRectEnd = new Point(Math.max(x1, x2), Math.max(y1, y2));
341
342 // calc the screen coordinates for the new selection rectangle
343 MapMarkerDot xmin_ymin = new MapMarkerDot(bbox.getMinLat(), bbox.getMinLon());
344 MapMarkerDot xmax_ymax = new MapMarkerDot(bbox.getMaxLat(), bbox.getMaxLon());
345
346 List<MapMarker> marker = new ArrayList<>(2);
347 marker.add(xmin_ymin);
348 marker.add(xmax_ymax);
349 setMapMarkerList(marker);
350 setDisplayToFitMapMarkers();
351 zoomOut();
352 repaint();
353 }
354
355 /**
356 * Refreshes the tile sources
357 * @since 6364
358 */
359 public final void refreshTileSources() {
360 iSourceButton.setSources(getAllTileSources());
361 }
362}
Note: See TracBrowser for help on using the repository browser.