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

Last change on this file since 8732 was 8732, checked in by simon04, 9 years ago

see #11823 - Minimap: hide shrink/enlarge button

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