source: osm/applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java@ 29188

Last change on this file since 29188 was 29188, checked in by the111, 12 years ago

Fix #josm8343 - remove "focus" from zoom slider

File size: 33.7 KB
Line 
1package org.openstreetmap.gui.jmapviewer;
2
3//License: GPL. Copyright 2008 by Jan Peter Stotz
4
5import java.awt.Dimension;
6import java.awt.Font;
7import java.awt.Graphics;
8import java.awt.Insets;
9import java.awt.Point;
10import java.awt.event.ActionEvent;
11import java.awt.event.ActionListener;
12import java.awt.event.MouseEvent;
13import java.util.LinkedList;
14import java.util.List;
15
16import javax.swing.ImageIcon;
17import javax.swing.JButton;
18import javax.swing.JPanel;
19import javax.swing.JSlider;
20import javax.swing.event.ChangeEvent;
21import javax.swing.event.ChangeListener;
22import javax.swing.event.EventListenerList;
23
24import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent;
25import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent.COMMAND;
26import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener;
27import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
28import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
29import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
30import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
31import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
32import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
33import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
34import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
35
36/**
37 *
38 * Provides a simple panel that displays pre-rendered map tiles loaded from the
39 * OpenStreetMap project.
40 *
41 * @author Jan Peter Stotz
42 *
43 */
44public class JMapViewer extends JPanel implements TileLoaderListener {
45
46 private static final long serialVersionUID = 1L;
47
48 /**
49 * Vectors for clock-wise tile painting
50 */
51 protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) };
52
53 public static final int MAX_ZOOM = 22;
54 public static final int MIN_ZOOM = 0;
55
56 protected List<MapMarker> mapMarkerList;
57 protected List<MapRectangle> mapRectangleList;
58 protected List<MapPolygon> mapPolygonList;
59
60 protected boolean mapMarkersVisible;
61 protected boolean mapRectanglesVisible;
62 protected boolean mapPolygonsVisible;
63
64 protected boolean tileGridVisible;
65 protected boolean scrollWrapEnabled;
66
67 protected TileController tileController;
68
69 /**
70 * x- and y-position of the center of this map-panel on the world map
71 * denoted in screen pixel regarding the current zoom level.
72 */
73 protected Point center;
74
75 /**
76 * Current zoom level
77 */
78 protected int zoom;
79
80 protected JSlider zoomSlider;
81 protected JButton zoomInButton;
82 protected JButton zoomOutButton;
83
84 public static enum ZOOM_BUTTON_STYLE {
85 HORIZONTAL,
86 VERTICAL
87 }
88 protected ZOOM_BUTTON_STYLE zoomButtonStyle;
89
90 private TileSource tileSource;
91
92 protected AttributionSupport attribution = new AttributionSupport();
93
94 /**
95 * Creates a standard {@link JMapViewer} instance that can be controlled via
96 * mouse: hold right mouse button for moving, double click left mouse button
97 * or use mouse wheel for zooming. Loaded tiles are stored the
98 * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for
99 * retrieving the tiles.
100 */
101 public JMapViewer() {
102 this(new MemoryTileCache(), 8);
103 new DefaultMapController(this);
104 }
105
106 public JMapViewer(TileCache tileCache, int downloadThreadCount) {
107 super();
108 JobDispatcher.setMaxWorkers(downloadThreadCount);
109 tileSource = new OsmTileSource.Mapnik();
110 tileController = new TileController(tileSource, tileCache, this);
111 mapMarkerList = new LinkedList<MapMarker>();
112 mapPolygonList = new LinkedList<MapPolygon>();
113 mapRectangleList = new LinkedList<MapRectangle>();
114 mapMarkersVisible = true;
115 mapRectanglesVisible = true;
116 mapPolygonsVisible = true;
117 tileGridVisible = false;
118 setLayout(null);
119 initializeZoomSlider();
120 setMinimumSize(new Dimension(tileSource.getTileSize(), tileSource.getTileSize()));
121 setPreferredSize(new Dimension(400, 400));
122 setDisplayPositionByLatLon(50, 9, 3);
123 //setToolTipText("");
124 }
125
126 @Override
127 public String getToolTipText(MouseEvent event) {
128 // Point screenPoint = event.getLocationOnScreen();
129 // Coordinate c = getPosition(screenPoint);
130 return super.getToolTipText(event);
131 }
132
133 protected void initializeZoomSlider() {
134 zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom());
135 zoomSlider.setOrientation(JSlider.VERTICAL);
136 zoomSlider.setBounds(10, 10, 30, 150);
137 zoomSlider.setOpaque(false);
138 zoomSlider.addChangeListener(new ChangeListener() {
139 public void stateChanged(ChangeEvent e) {
140 setZoom(zoomSlider.getValue());
141 }
142 });
143 zoomSlider.setFocusable(false);
144 add(zoomSlider);
145 int size = 18;
146 try {
147 ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/plus.png"));
148 zoomInButton = new JButton(icon);
149 } catch (Exception e) {
150 zoomInButton = new JButton("+");
151 zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9));
152 zoomInButton.setMargin(new Insets(0, 0, 0, 0));
153 }
154 zoomInButton.setBounds(4, 155, size, size);
155 zoomInButton.addActionListener(new ActionListener() {
156
157 public void actionPerformed(ActionEvent e) {
158 zoomIn();
159 }
160 });
161 zoomInButton.setFocusable(false);
162 add(zoomInButton);
163 try {
164 ImageIcon icon = new ImageIcon(JMapViewer.class.getResource("images/minus.png"));
165 zoomOutButton = new JButton(icon);
166 } catch (Exception e) {
167 zoomOutButton = new JButton("-");
168 zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9));
169 zoomOutButton.setMargin(new Insets(0, 0, 0, 0));
170 }
171 zoomOutButton.setBounds(8 + size, 155, size, size);
172 zoomOutButton.addActionListener(new ActionListener() {
173
174 public void actionPerformed(ActionEvent e) {
175 zoomOut();
176 }
177 });
178 zoomOutButton.setFocusable(false);
179 add(zoomOutButton);
180 }
181
182 /**
183 * Changes the map pane so that it is centered on the specified coordinate
184 * at the given zoom level.
185 *
186 * @param lat
187 * latitude of the specified coordinate
188 * @param lon
189 * longitude of the specified coordinate
190 * @param zoom
191 * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM}
192 */
193 public void setDisplayPositionByLatLon(double lat, double lon, int zoom) {
194 setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), lat, lon, zoom);
195 }
196
197 /**
198 * Changes the map pane so that the specified coordinate at the given zoom
199 * level is displayed on the map at the screen coordinate
200 * <code>mapPoint</code>.
201 *
202 * @param mapPoint
203 * point on the map denoted in pixels where the coordinate should
204 * be set
205 * @param lat
206 * latitude of the specified coordinate
207 * @param lon
208 * longitude of the specified coordinate
209 * @param zoom
210 * {@link #MIN_ZOOM} <= zoom level <=
211 * {@link TileSource#getMaxZoom()}
212 */
213 public void setDisplayPositionByLatLon(Point mapPoint, double lat, double lon, int zoom) {
214 int x = OsmMercator.LonToX(lon, zoom);
215 int y = OsmMercator.LatToY(lat, zoom);
216 setDisplayPosition(mapPoint, x, y, zoom);
217 }
218
219 public void setDisplayPosition(int x, int y, int zoom) {
220 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom);
221 }
222
223 public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) {
224 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < MIN_ZOOM)
225 return;
226
227 // Get the plain tile number
228 Point p = new Point();
229 p.x = x - mapPoint.x + getWidth() / 2;
230 p.y = y - mapPoint.y + getHeight() / 2;
231 center = p;
232 setIgnoreRepaint(true);
233 try {
234 int oldZoom = this.zoom;
235 this.zoom = zoom;
236 if (oldZoom != zoom) {
237 zoomChanged(oldZoom);
238 }
239 if (zoomSlider.getValue() != zoom) {
240 zoomSlider.setValue(zoom);
241 }
242 } finally {
243 setIgnoreRepaint(false);
244 repaint();
245 }
246 }
247
248 /**
249 * Sets the displayed map pane and zoom level so that all chosen map elements are
250 * visible.
251 */
252 public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) {
253 int nbElemToCheck = 0;
254 if (markers && mapMarkerList != null)
255 nbElemToCheck += mapMarkerList.size();
256 if (rectangles && mapRectangleList != null)
257 nbElemToCheck += mapRectangleList.size();
258 if (polygons && mapPolygonList != null)
259 nbElemToCheck += mapPolygonList.size();
260 if (nbElemToCheck == 0)
261 return;
262
263 int x_min = Integer.MAX_VALUE;
264 int y_min = Integer.MAX_VALUE;
265 int x_max = Integer.MIN_VALUE;
266 int y_max = Integer.MIN_VALUE;
267 int mapZoomMax = tileController.getTileSource().getMaxZoom();
268
269 if (markers) {
270 for (MapMarker marker : mapMarkerList) {
271 int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
272 int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
273 x_max = Math.max(x_max, x);
274 y_max = Math.max(y_max, y);
275 x_min = Math.min(x_min, x);
276 y_min = Math.min(y_min, y);
277 }
278 }
279
280 if (rectangles) {
281 for (MapRectangle rectangle : mapRectangleList) {
282 x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
283 y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
284 x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
285 y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
286 }
287 }
288
289 if (polygons) {
290 for (MapPolygon polygon : mapPolygonList) {
291 for (Coordinate c : polygon.getPoints()) {
292 int x = OsmMercator.LonToX(c.getLon(), mapZoomMax);
293 int y = OsmMercator.LatToY(c.getLat(), mapZoomMax);
294 x_max = Math.max(x_max, x);
295 y_max = Math.max(y_max, y);
296 x_min = Math.min(x_min, x);
297 y_min = Math.min(y_min, y);
298 }
299 }
300 }
301
302 int height = Math.max(0, getHeight());
303 int width = Math.max(0, getWidth());
304 int newZoom = mapZoomMax;
305 int x = x_max - x_min;
306 int y = y_max - y_min;
307 while (x > width || y > height) {
308 newZoom--;
309 x >>= 1;
310 y >>= 1;
311 }
312 x = x_min + (x_max - x_min) / 2;
313 y = y_min + (y_max - y_min) / 2;
314 int z = 1 << (mapZoomMax - newZoom);
315 x /= z;
316 y /= z;
317 setDisplayPosition(x, y, newZoom);
318 }
319
320
321 /**
322 * Sets the displayed map pane and zoom level so that all map markers are
323 * visible.
324 */
325 public void setDisplayToFitMapMarkers() {
326 setDisplayToFitMapElements(true, false, false);
327 }
328
329 /**
330 * Sets the displayed map pane and zoom level so that all map rectangles are
331 * visible.
332 */
333 public void setDisplayToFitMapRectangles() {
334 setDisplayToFitMapElements(false, true, false);
335 }
336
337 /**
338 * Sets the displayed map pane and zoom level so that all map polygons are
339 * visible.
340 */
341 public void setDisplayToFitMapPolygons() {
342 setDisplayToFitMapElements(false, false, true);
343 }
344
345 /**
346 * @return the center
347 */
348 public Point getCenter() {
349 return center;
350 }
351
352 /**
353 * @param center the center to set
354 */
355 public void setCenter(Point center) {
356 this.center = center;
357 }
358
359 /**
360 * Calculates the latitude/longitude coordinate of the center of the
361 * currently displayed map area.
362 *
363 * @return latitude / longitude
364 */
365 public Coordinate getPosition() {
366 double lon = OsmMercator.XToLon(center.x, zoom);
367 double lat = OsmMercator.YToLat(center.y, zoom);
368 return new Coordinate(lat, lon);
369 }
370
371 /**
372 * Converts the relative pixel coordinate (regarding the top left corner of
373 * the displayed map) into a latitude / longitude coordinate
374 *
375 * @param mapPoint
376 * relative pixel coordinate regarding the top left corner of the
377 * displayed map
378 * @return latitude / longitude
379 */
380 public Coordinate getPosition(Point mapPoint) {
381 return getPosition(mapPoint.x, mapPoint.y);
382 }
383
384 /**
385 * Converts the relative pixel coordinate (regarding the top left corner of
386 * the displayed map) into a latitude / longitude coordinate
387 *
388 * @param mapPointX
389 * @param mapPointY
390 * @return latitude / longitude
391 */
392 public Coordinate getPosition(int mapPointX, int mapPointY) {
393 int x = center.x + mapPointX - getWidth() / 2;
394 int y = center.y + mapPointY - getHeight() / 2;
395 double lon = OsmMercator.XToLon(x, zoom);
396 double lat = OsmMercator.YToLat(y, zoom);
397 return new Coordinate(lat, lon);
398 }
399
400 /**
401 * Calculates the position on the map of a given coordinate
402 *
403 * @param lat
404 * @param lon
405 * @param checkOutside
406 * @return point on the map or <code>null</code> if the point is not visible
407 * and checkOutside set to <code>true</code>
408 */
409 public Point getMapPosition(double lat, double lon, boolean checkOutside) {
410 int x = OsmMercator.LonToX(lon, zoom);
411 int y = OsmMercator.LatToY(lat, zoom);
412 x -= center.x - getWidth() / 2;
413 y -= center.y - getHeight() / 2;
414 if (checkOutside) {
415 if (x < 0 || y < 0 || x > getWidth() || y > getHeight())
416 return null;
417 }
418 return new Point(x, y);
419 }
420
421 /**
422 * Calculates the position on the map of a given coordinate
423 *
424 * @param lat
425 * @param lon
426 * @return point on the map or <code>null</code> if the point is not visible
427 */
428 public Point getMapPosition(double lat, double lon) {
429 return getMapPosition(lat, lon, true);
430 }
431
432 /**
433 * Calculates the position on the map of a given coordinate
434 *
435 * @param coord
436 * @return point on the map or <code>null</code> if the point is not visible
437 */
438 public Point getMapPosition(Coordinate coord) {
439 if (coord != null)
440 return getMapPosition(coord.getLat(), coord.getLon());
441 else
442 return null;
443 }
444
445 /**
446 * Calculates the position on the map of a given coordinate
447 *
448 * @param coord
449 * @return point on the map or <code>null</code> if the point is not visible
450 * and checkOutside set to <code>true</code>
451 */
452 public Point getMapPosition(Coordinate coord, boolean checkOutside) {
453 if (coord != null)
454 return getMapPosition(coord.getLat(), coord.getLon(), checkOutside);
455 else
456 return null;
457 }
458
459 /**
460 * Gets the meter per pixel.
461 *
462 * @return the meter per pixel
463 * @author Jason Huntley
464 */
465 public double getMeterPerPixel() {
466 Point origin=new Point(5,5);
467 Point center=new Point(getWidth()/2, getHeight()/2);
468
469 double pDistance=center.distance(origin);
470
471 Coordinate originCoord=getPosition(origin);
472 Coordinate centerCoord=getPosition(center);
473
474 double mDistance=OsmMercator.getDistance(originCoord.getLat(), originCoord.getLon(),
475 centerCoord.getLat(), centerCoord.getLon());
476
477 return mDistance/pDistance;
478 }
479
480 @Override
481 protected void paintComponent(Graphics g) {
482 super.paintComponent(g);
483
484 int iMove = 0;
485
486 int tilesize = tileSource.getTileSize();
487 int tilex = center.x / tilesize;
488 int tiley = center.y / tilesize;
489 int off_x = (center.x % tilesize);
490 int off_y = (center.y % tilesize);
491
492 int w2 = getWidth() / 2;
493 int h2 = getHeight() / 2;
494 int posx = w2 - off_x;
495 int posy = h2 - off_y;
496
497 int diff_left = off_x;
498 int diff_right = tilesize - off_x;
499 int diff_top = off_y;
500 int diff_bottom = tilesize - off_y;
501
502 boolean start_left = diff_left < diff_right;
503 boolean start_top = diff_top < diff_bottom;
504
505 if (start_top) {
506 if (start_left) {
507 iMove = 2;
508 } else {
509 iMove = 3;
510 }
511 } else {
512 if (start_left) {
513 iMove = 1;
514 } else {
515 iMove = 0;
516 }
517 } // calculate the visibility borders
518 int x_min = -tilesize;
519 int y_min = -tilesize;
520 int x_max = getWidth();
521 int y_max = getHeight();
522
523 // calculate the length of the grid (number of squares per edge)
524 int gridLength = 1 << zoom;
525
526 // paint the tiles in a spiral, starting from center of the map
527 boolean painted = true;
528 int x = 0;
529 while (painted) {
530 painted = false;
531 for (int i = 0; i < 4; i++) {
532 if (i % 2 == 0) {
533 x++;
534 }
535 for (int j = 0; j < x; j++) {
536 if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) {
537 // tile is visible
538 Tile tile;
539 if (scrollWrapEnabled) {
540 // in case tilex is out of bounds, grab the tile to use for wrapping
541 int tilexWrap = (((tilex % gridLength) + gridLength) % gridLength);
542 tile = tileController.getTile(tilexWrap, tiley, zoom);
543 } else {
544 tile = tileController.getTile(tilex, tiley, zoom);
545 }
546 if (tile != null) {
547 tile.paint(g, posx, posy);
548 if (tileGridVisible) {
549 g.drawRect(posx, posy, tilesize, tilesize);
550 }
551 }
552 painted = true;
553 }
554 Point p = move[iMove];
555 posx += p.x * tilesize;
556 posy += p.y * tilesize;
557 tilex += p.x;
558 tiley += p.y;
559 }
560 iMove = (iMove + 1) % move.length;
561 }
562 }
563 // outer border of the map
564 int mapSize = tilesize << zoom;
565 if (scrollWrapEnabled) {
566 g.drawLine(0, h2 - center.y, getWidth(), h2 - center.y);
567 g.drawLine(0, h2 - center.y + mapSize, getWidth(), h2 - center.y + mapSize);
568 } else {
569 g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize);
570 }
571
572 // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20);
573
574 // keep x-coordinates from growing without bound if scroll-wrap is enabled
575 if (scrollWrapEnabled) {
576 center.x = center.x % mapSize;
577 }
578
579 if (mapPolygonsVisible && mapPolygonList != null) {
580 for (MapPolygon polygon : mapPolygonList) {
581 paintPolygon(g, polygon);
582 }
583 }
584
585 if (mapRectanglesVisible && mapRectangleList != null) {
586 for (MapRectangle rectangle : mapRectangleList) {
587 paintRectangle(g, rectangle);
588 }
589 }
590
591 if (mapMarkersVisible && mapMarkerList != null) {
592 for (MapMarker marker : mapMarkerList) {
593 paintMarker(g, marker);
594 }
595 }
596
597 attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this);
598 }
599
600 /**
601 * Paint a single marker.
602 */
603 protected void paintMarker(Graphics g, MapMarker marker) {
604 Point p = getMapPosition(marker.getLat(), marker.getLon());
605 if (scrollWrapEnabled) {
606 int tilesize = tileSource.getTileSize();
607 int mapSize = tilesize << zoom;
608 if (p == null) {
609 p = getMapPosition(marker.getLat(), marker.getLon(), false);
610 }
611 marker.paint(g, p);
612 int xSave = p.x;
613 int xWrap = xSave;
614 // overscan of 15 allows up to 30-pixel markers to gracefully scroll off the edge of the panel
615 while ((xWrap -= mapSize) >= -15) {
616 p.x = xWrap;
617 marker.paint(g, p);
618 }
619 xWrap = xSave;
620 while ((xWrap += mapSize) <= getWidth() + 15) {
621 p.x = xWrap;
622 marker.paint(g, p);
623 }
624 } else {
625 if (p != null) {
626 marker.paint(g, p);
627 }
628 }
629 }
630
631 /**
632 * Paint a single rectangle.
633 */
634 protected void paintRectangle(Graphics g, MapRectangle rectangle) {
635 Coordinate topLeft = rectangle.getTopLeft();
636 Coordinate bottomRight = rectangle.getBottomRight();
637 if (topLeft != null && bottomRight != null) {
638 Point pTopLeft = getMapPosition(topLeft, false);
639 Point pBottomRight = getMapPosition(bottomRight, false);
640 if (pTopLeft != null && pBottomRight != null) {
641 rectangle.paint(g, pTopLeft, pBottomRight);
642 if (scrollWrapEnabled) {
643 int tilesize = tileSource.getTileSize();
644 int mapSize = tilesize << zoom;
645 int xTopLeftSave = pTopLeft.x;
646 int xTopLeftWrap = xTopLeftSave;
647 int xBottomRightSave = pBottomRight.x;
648 int xBottomRightWrap = xBottomRightSave;
649 while ((xBottomRightWrap -= mapSize) >= 0) {
650 xTopLeftWrap -= mapSize;
651 pTopLeft.x = xTopLeftWrap;
652 pBottomRight.x = xBottomRightWrap;
653 rectangle.paint(g, pTopLeft, pBottomRight);
654 }
655 xTopLeftWrap = xTopLeftSave;
656 xBottomRightWrap = xBottomRightSave;
657 while ((xTopLeftWrap += mapSize) <= getWidth()) {
658 xBottomRightWrap += mapSize;
659 pTopLeft.x = xTopLeftWrap;
660 pBottomRight.x = xBottomRightWrap;
661 rectangle.paint(g, pTopLeft, pBottomRight);
662 }
663
664 }
665 }
666 }
667 }
668
669 /**
670 * Paint a single polygon.
671 */
672 protected void paintPolygon(Graphics g, MapPolygon polygon) {
673 List<Coordinate> coords = polygon.getPoints();
674 if (coords != null && coords.size() >= 3) {
675 List<Point> points = new LinkedList<Point>();
676 for (Coordinate c : coords) {
677 Point p = getMapPosition(c, false);
678 if (p == null) {
679 return;
680 }
681 points.add(p);
682 }
683 polygon.paint(g, points);
684 if (scrollWrapEnabled) {
685 int tilesize = tileSource.getTileSize();
686 int mapSize = tilesize << zoom;
687 List<Point> pointsWrapped = new LinkedList<Point>(points);
688 boolean keepWrapping = true;
689 while (keepWrapping) {
690 for (Point p : pointsWrapped) {
691 p.x -= mapSize;
692 if (p.x < 0) {
693 keepWrapping = false;
694 }
695 }
696 polygon.paint(g, pointsWrapped);
697 }
698 pointsWrapped = new LinkedList<Point>(points);
699 keepWrapping = true;
700 while (keepWrapping) {
701 for (Point p : pointsWrapped) {
702 p.x += mapSize;
703 if (p.x > getWidth()) {
704 keepWrapping = false;
705 }
706 }
707 polygon.paint(g, pointsWrapped);
708 }
709 }
710 }
711 }
712
713 /**
714 * Moves the visible map pane.
715 *
716 * @param x
717 * horizontal movement in pixel.
718 * @param y
719 * vertical movement in pixel
720 */
721 public void moveMap(int x, int y) {
722 tileController.cancelOutstandingJobs(); // Clear outstanding load
723 center.x += x;
724 center.y += y;
725 repaint();
726 this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this));
727 }
728
729 /**
730 * @return the current zoom level
731 */
732 public int getZoom() {
733 return zoom;
734 }
735
736 /**
737 * Increases the current zoom level by one
738 */
739 public void zoomIn() {
740 setZoom(zoom + 1);
741 }
742
743 /**
744 * Increases the current zoom level by one
745 */
746 public void zoomIn(Point mapPoint) {
747 setZoom(zoom + 1, mapPoint);
748 }
749
750 /**
751 * Decreases the current zoom level by one
752 */
753 public void zoomOut() {
754 setZoom(zoom - 1);
755 }
756
757 /**
758 * Decreases the current zoom level by one
759 *
760 * @param mapPoint point to choose as center for new zoom level
761 */
762 public void zoomOut(Point mapPoint) {
763 setZoom(zoom - 1, mapPoint);
764 }
765
766 /**
767 * Set the zoom level and center point for display
768 *
769 * @param zoom new zoom level
770 * @param mapPoint point to choose as center for new zoom level
771 */
772 public void setZoom(int zoom, Point mapPoint) {
773 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom()
774 || zoom == this.zoom)
775 return;
776 Coordinate zoomPos = getPosition(mapPoint);
777 tileController.cancelOutstandingJobs(); // Clearing outstanding load
778 // requests
779 setDisplayPositionByLatLon(mapPoint, zoomPos.getLat(), zoomPos.getLon(), zoom);
780
781 this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this));
782 }
783
784 /**
785 * Set the zoom level
786 *
787 * @param zoom new zoom level
788 */
789 public void setZoom(int zoom) {
790 setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2));
791 }
792
793 /**
794 * Every time the zoom level changes this method is called. Override it in
795 * derived implementations for adapting zoom dependent values. The new zoom
796 * level can be obtained via {@link #getZoom()}.
797 *
798 * @param oldZoom
799 * the previous zoom level
800 */
801 protected void zoomChanged(int oldZoom) {
802 zoomSlider.setToolTipText("Zoom level " + zoom);
803 zoomInButton.setToolTipText("Zoom to level " + (zoom + 1));
804 zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1));
805 zoomOutButton.setEnabled(zoom > tileController.getTileSource().getMinZoom());
806 zoomInButton.setEnabled(zoom < tileController.getTileSource().getMaxZoom());
807 }
808
809 public boolean isTileGridVisible() {
810 return tileGridVisible;
811 }
812
813 public void setTileGridVisible(boolean tileGridVisible) {
814 this.tileGridVisible = tileGridVisible;
815 repaint();
816 }
817
818 public boolean getMapMarkersVisible() {
819 return mapMarkersVisible;
820 }
821
822 /**
823 * Enables or disables painting of the {@link MapMarker}
824 *
825 * @param mapMarkersVisible
826 * @see #addMapMarker(MapMarker)
827 * @see #getMapMarkerList()
828 */
829 public void setMapMarkerVisible(boolean mapMarkersVisible) {
830 this.mapMarkersVisible = mapMarkersVisible;
831 repaint();
832 }
833
834 public void setMapMarkerList(List<MapMarker> mapMarkerList) {
835 this.mapMarkerList = mapMarkerList;
836 repaint();
837 }
838
839 public List<MapMarker> getMapMarkerList() {
840 return mapMarkerList;
841 }
842
843 public void setMapRectangleList(List<MapRectangle> mapRectangleList) {
844 this.mapRectangleList = mapRectangleList;
845 repaint();
846 }
847
848 public List<MapRectangle> getMapRectangleList() {
849 return mapRectangleList;
850 }
851
852 public void setMapPolygonList(List<MapPolygon> mapPolygonList) {
853 this.mapPolygonList = mapPolygonList;
854 repaint();
855 }
856
857 public List<MapPolygon> getMapPolygonList() {
858 return mapPolygonList;
859 }
860
861 public void addMapMarker(MapMarker marker) {
862 mapMarkerList.add(marker);
863 repaint();
864 }
865
866 public void removeMapMarker(MapMarker marker) {
867 mapMarkerList.remove(marker);
868 repaint();
869 }
870
871 public void removeAllMapMarkers() {
872 mapMarkerList.clear();
873 repaint();
874 }
875
876 public void addMapRectangle(MapRectangle rectangle) {
877 mapRectangleList.add(rectangle);
878 repaint();
879 }
880
881 public void removeMapRectangle(MapRectangle rectangle) {
882 mapRectangleList.remove(rectangle);
883 repaint();
884 }
885
886 public void removeAllMapRectangles() {
887 mapRectangleList.clear();
888 repaint();
889 }
890
891 public void addMapPolygon(MapPolygon polygon) {
892 mapPolygonList.add(polygon);
893 repaint();
894 }
895
896 public void removeMapPolygon(MapPolygon polygon) {
897 mapPolygonList.remove(polygon);
898 repaint();
899 }
900
901 public void removeAllMapPolygons() {
902 mapPolygonList.clear();
903 repaint();
904 }
905
906 public void setZoomContolsVisible(boolean visible) {
907 zoomSlider.setVisible(visible);
908 zoomInButton.setVisible(visible);
909 zoomOutButton.setVisible(visible);
910 }
911
912 public boolean getZoomContolsVisible() {
913 return zoomSlider.isVisible();
914 }
915
916 public void setTileSource(TileSource tileSource) {
917 if (tileSource.getMaxZoom() > MAX_ZOOM)
918 throw new RuntimeException("Maximum zoom level too high");
919 if (tileSource.getMinZoom() < MIN_ZOOM)
920 throw new RuntimeException("Minumim zoom level too low");
921 this.tileSource = tileSource;
922 tileController.setTileSource(tileSource);
923 zoomSlider.setMinimum(tileSource.getMinZoom());
924 zoomSlider.setMaximum(tileSource.getMaxZoom());
925 tileController.cancelOutstandingJobs();
926 if (zoom > tileSource.getMaxZoom()) {
927 setZoom(tileSource.getMaxZoom());
928 }
929
930 attribution.initialize(tileSource);
931 repaint();
932 }
933
934 public void tileLoadingFinished(Tile tile, boolean success) {
935 repaint();
936 }
937
938 public boolean isMapRectanglesVisible() {
939 return mapRectanglesVisible;
940 }
941
942 /**
943 * Enables or disables painting of the {@link MapRectangle}
944 *
945 * @param mapRectanglesVisible
946 * @see #addMapRectangle(MapRectangle)
947 * @see #getMapRectangleList()
948 */
949 public void setMapRectanglesVisible(boolean mapRectanglesVisible) {
950 this.mapRectanglesVisible = mapRectanglesVisible;
951 repaint();
952 }
953
954 public boolean isMapPolygonsVisible() {
955 return mapPolygonsVisible;
956 }
957
958 /**
959 * Enables or disables painting of the {@link MapPolygon}
960 *
961 * @param mapPolygonsVisible
962 * @see #addMapPolygon(MapPolygon)
963 * @see #getMapPolygonList()
964 */
965 public void setMapPolygonsVisible(boolean mapPolygonsVisible) {
966 this.mapPolygonsVisible = mapPolygonsVisible;
967 repaint();
968 }
969
970 public boolean isScrollWrapEnabled() {
971 return scrollWrapEnabled;
972 }
973
974 public void setScrollWrapEnabled(boolean scrollWrapEnabled) {
975 this.scrollWrapEnabled = scrollWrapEnabled;
976 repaint();
977 }
978
979 public ZOOM_BUTTON_STYLE getZoomButtonStyle() {
980 return zoomButtonStyle;
981 }
982
983 public void setZoomButtonStyle(ZOOM_BUTTON_STYLE style) {
984 zoomButtonStyle = style;
985 if (zoomSlider == null || zoomInButton == null || zoomOutButton == null) {
986 return;
987 }
988 switch (style) {
989 case HORIZONTAL:
990 zoomSlider.setBounds(10, 10, 30, 150);
991 zoomInButton.setBounds(4, 155, 18, 18);
992 zoomOutButton.setBounds(26, 155, 18, 18);
993 break;
994 case VERTICAL:
995 zoomSlider.setBounds(10, 27, 30, 150);
996 zoomInButton.setBounds(14, 8, 20, 20);
997 zoomOutButton.setBounds(14, 176, 20, 20);
998 break;
999 default:
1000 zoomSlider.setBounds(10, 10, 30, 150);
1001 zoomInButton.setBounds(4, 155, 18, 18);
1002 zoomOutButton.setBounds(26, 155, 18, 18);
1003 break;
1004 }
1005 repaint();
1006 }
1007
1008 /**
1009 * Return tile information caching class
1010 * @see TileLoaderListener#getTileCache()
1011 */
1012 public TileCache getTileCache() {
1013 return tileController.getTileCache();
1014 }
1015
1016 public void setTileLoader(TileLoader loader) {
1017 tileController.setTileLoader(loader);
1018 }
1019
1020 protected EventListenerList listenerList = new EventListenerList();
1021
1022 /**
1023 * @param listener listener to set
1024 */
1025 public void addJMVListener(JMapViewerEventListener listener) {
1026 listenerList.add(JMapViewerEventListener.class, listener);
1027 }
1028
1029 /**
1030 * @param listener listener to remove
1031 */
1032 public void removeJMVListener(JMapViewerEventListener listener) {
1033 listenerList.remove(JMapViewerEventListener.class, listener);
1034 }
1035
1036 /**
1037 * Send an update to all objects registered with viewer
1038 *
1039 * @param event to dispatch
1040 */
1041 void fireJMVEvent(JMVCommandEvent evt) {
1042 Object[] listeners = listenerList.getListenerList();
1043 for (int i=0; i<listeners.length; i+=2) {
1044 if (listeners[i]==JMapViewerEventListener.class) {
1045 ((JMapViewerEventListener)listeners[i+1]).processCommand(evt);
1046 }
1047 }
1048 }
1049}
Note: See TracBrowser for help on using the repository browser.