001 package org.openstreetmap.gui.jmapviewer;
002
003 //License: GPL. Copyright 2008 by Jan Peter Stotz
004
005 import java.awt.Color;
006 import java.awt.Dimension;
007 import java.awt.Font;
008 import java.awt.Graphics;
009 import java.awt.Image;
010 import java.awt.Insets;
011 import java.awt.Point;
012 import java.awt.Rectangle;
013 import java.awt.event.ActionEvent;
014 import java.awt.event.ActionListener;
015 import java.awt.event.MouseEvent;
016 import java.awt.font.TextAttribute;
017 import java.awt.geom.Rectangle2D;
018 import java.util.HashMap;
019 import java.util.LinkedList;
020 import java.util.List;
021
022 import javax.swing.ImageIcon;
023 import javax.swing.JButton;
024 import javax.swing.JPanel;
025 import javax.swing.JSlider;
026 import javax.swing.event.ChangeEvent;
027 import javax.swing.event.ChangeListener;
028 import javax.swing.event.EventListenerList;
029
030 import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent;
031 import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent.COMMAND;
032 import org.openstreetmap.gui.jmapviewer.interfaces.JMapViewerEventListener;
033 import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
034 import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
035 import org.openstreetmap.gui.jmapviewer.interfaces.MapRectangle;
036 import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
037 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
038 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
039 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
040 import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
041
042 /**
043 *
044 * Provides a simple panel that displays pre-rendered map tiles loaded from the
045 * OpenStreetMap project.
046 *
047 * @author Jan Peter Stotz
048 *
049 */
050 public class JMapViewer extends JPanel implements TileLoaderListener {
051
052 private static final long serialVersionUID = 1L;
053
054 /**
055 * Vectors for clock-wise tile painting
056 */
057 protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) };
058
059 public static final int MAX_ZOOM = 22;
060 public static final int MIN_ZOOM = 0;
061
062 protected List<MapMarker> mapMarkerList;
063 protected List<MapRectangle> mapRectangleList;
064 protected List<MapPolygon> mapPolygonList;
065
066 protected boolean mapMarkersVisible;
067 protected boolean mapRectanglesVisible;
068 protected boolean mapPolygonsVisible;
069
070 protected boolean tileGridVisible;
071
072 protected TileController tileController;
073
074 /**
075 * x- and y-position of the center of this map-panel on the world map
076 * denoted in screen pixel regarding the current zoom level.
077 */
078 protected Point center;
079
080 /**
081 * Current zoom level
082 */
083 protected int zoom;
084
085 protected JSlider zoomSlider;
086 protected JButton zoomInButton;
087 protected JButton zoomOutButton;
088
089 private TileSource tileSource;
090
091 protected AttributionSupport attribution = new AttributionSupport();
092
093 /**
094 * Creates a standard {@link JMapViewer} instance that can be controlled via
095 * mouse: hold right mouse button for moving, double click left mouse button
096 * or use mouse wheel for zooming. Loaded tiles are stored the
097 * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for
098 * retrieving the tiles.
099 */
100 public JMapViewer() {
101 this(new MemoryTileCache(), 4);
102 new DefaultMapController(this);
103 }
104
105 public JMapViewer(TileCache tileCache, int downloadThreadCount) {
106 super();
107 tileSource = new OsmTileSource.Mapnik();
108 tileController = new TileController(tileSource, tileCache, this);
109 mapMarkerList = new LinkedList<MapMarker>();
110 mapPolygonList = new LinkedList<MapPolygon>();
111 mapRectangleList = new LinkedList<MapRectangle>();
112 mapMarkersVisible = true;
113 mapRectanglesVisible = true;
114 mapPolygonsVisible = true;
115 tileGridVisible = false;
116 setLayout(null);
117 initializeZoomSlider();
118 setMinimumSize(new Dimension(tileSource.getTileSize(), tileSource.getTileSize()));
119 setPreferredSize(new Dimension(400, 400));
120 setDisplayPositionByLatLon(50, 9, 3);
121 //setToolTipText("");
122 }
123
124 @Override
125 public String getToolTipText(MouseEvent event) {
126 // Point screenPoint = event.getLocationOnScreen();
127 // Coordinate c = getPosition(screenPoint);
128 return super.getToolTipText(event);
129 }
130
131 protected void initializeZoomSlider() {
132 zoomSlider = new JSlider(MIN_ZOOM, tileController.getTileSource().getMaxZoom());
133 zoomSlider.setOrientation(JSlider.VERTICAL);
134 zoomSlider.setBounds(10, 10, 30, 150);
135 zoomSlider.setOpaque(false);
136 zoomSlider.addChangeListener(new ChangeListener() {
137 public void stateChanged(ChangeEvent e) {
138 setZoom(zoomSlider.getValue());
139 }
140 });
141 add(zoomSlider);
142 int size = 18;
143 try {
144 ImageIcon icon = new ImageIcon(getClass().getResource("images/plus.png"));
145 zoomInButton = new JButton(icon);
146 } catch (Exception e) {
147 zoomInButton = new JButton("+");
148 zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9));
149 zoomInButton.setMargin(new Insets(0, 0, 0, 0));
150 }
151 zoomInButton.setBounds(4, 155, size, size);
152 zoomInButton.addActionListener(new ActionListener() {
153
154 public void actionPerformed(ActionEvent e) {
155 zoomIn();
156 }
157 });
158 add(zoomInButton);
159 try {
160 ImageIcon icon = new ImageIcon(getClass().getResource("images/minus.png"));
161 zoomOutButton = new JButton(icon);
162 } catch (Exception e) {
163 zoomOutButton = new JButton("-");
164 zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9));
165 zoomOutButton.setMargin(new Insets(0, 0, 0, 0));
166 }
167 zoomOutButton.setBounds(8 + size, 155, size, size);
168 zoomOutButton.addActionListener(new ActionListener() {
169
170 public void actionPerformed(ActionEvent e) {
171 zoomOut();
172 }
173 });
174 add(zoomOutButton);
175 }
176
177 /**
178 * Changes the map pane so that it is centered on the specified coordinate
179 * at the given zoom level.
180 *
181 * @param lat
182 * latitude of the specified coordinate
183 * @param lon
184 * longitude of the specified coordinate
185 * @param zoom
186 * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM}
187 */
188 public void setDisplayPositionByLatLon(double lat, double lon, int zoom) {
189 setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), lat, lon, zoom);
190 }
191
192 /**
193 * Changes the map pane so that the specified coordinate at the given zoom
194 * level is displayed on the map at the screen coordinate
195 * <code>mapPoint</code>.
196 *
197 * @param mapPoint
198 * point on the map denoted in pixels where the coordinate should
199 * be set
200 * @param lat
201 * latitude of the specified coordinate
202 * @param lon
203 * longitude of the specified coordinate
204 * @param zoom
205 * {@link #MIN_ZOOM} <= zoom level <=
206 * {@link TileSource#getMaxZoom()}
207 */
208 public void setDisplayPositionByLatLon(Point mapPoint, double lat, double lon, int zoom) {
209 int x = OsmMercator.LonToX(lon, zoom);
210 int y = OsmMercator.LatToY(lat, zoom);
211 setDisplayPosition(mapPoint, x, y, zoom);
212 }
213
214 public void setDisplayPosition(int x, int y, int zoom) {
215 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom);
216 }
217
218 public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) {
219 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < MIN_ZOOM)
220 return;
221
222 // Get the plain tile number
223 Point p = new Point();
224 p.x = x - mapPoint.x + getWidth() / 2;
225 p.y = y - mapPoint.y + getHeight() / 2;
226 center = p;
227 setIgnoreRepaint(true);
228 try {
229 int oldZoom = this.zoom;
230 this.zoom = zoom;
231 if (oldZoom != zoom) {
232 zoomChanged(oldZoom);
233 }
234 if (zoomSlider.getValue() != zoom) {
235 zoomSlider.setValue(zoom);
236 }
237 } finally {
238 setIgnoreRepaint(false);
239 repaint();
240 }
241 }
242
243 /**
244 * Sets the displayed map pane and zoom level so that all chosen map elements are
245 * visible.
246 */
247 public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) {
248 int nbElemToCheck = 0;
249 if (markers && mapMarkerList != null)
250 nbElemToCheck += mapMarkerList.size();
251 if (rectangles && mapRectangleList != null)
252 nbElemToCheck += mapRectangleList.size();
253 if (polygons && mapPolygonList != null)
254 nbElemToCheck += mapPolygonList.size();
255 if (nbElemToCheck == 0)
256 return;
257
258 int x_min = Integer.MAX_VALUE;
259 int y_min = Integer.MAX_VALUE;
260 int x_max = Integer.MIN_VALUE;
261 int y_max = Integer.MIN_VALUE;
262 int mapZoomMax = tileController.getTileSource().getMaxZoom();
263
264 if (markers) {
265 for (MapMarker marker : mapMarkerList) {
266 int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
267 int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
268 x_max = Math.max(x_max, x);
269 y_max = Math.max(y_max, y);
270 x_min = Math.min(x_min, x);
271 y_min = Math.min(y_min, y);
272 }
273 }
274
275 if (rectangles) {
276 for (MapRectangle rectangle : mapRectangleList) {
277 x_max = Math.max(x_max, OsmMercator.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
278 y_max = Math.max(y_max, OsmMercator.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
279 x_min = Math.min(x_min, OsmMercator.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
280 y_min = Math.min(y_min, OsmMercator.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
281 }
282 }
283
284 if (polygons) {
285 for (MapPolygon polygon : mapPolygonList) {
286 for (Coordinate c : polygon.getPoints()) {
287 int x = OsmMercator.LonToX(c.getLon(), mapZoomMax);
288 int y = OsmMercator.LatToY(c.getLat(), mapZoomMax);
289 x_max = Math.max(x_max, x);
290 y_max = Math.max(y_max, y);
291 x_min = Math.min(x_min, x);
292 y_min = Math.min(y_min, y);
293 }
294 }
295 }
296
297 int height = Math.max(0, getHeight());
298 int width = Math.max(0, getWidth());
299 int newZoom = mapZoomMax;
300 int x = x_max - x_min;
301 int y = y_max - y_min;
302 while (x > width || y > height) {
303 newZoom--;
304 x >>= 1;
305 y >>= 1;
306 }
307 x = x_min + (x_max - x_min) / 2;
308 y = y_min + (y_max - y_min) / 2;
309 int z = 1 << (mapZoomMax - newZoom);
310 x /= z;
311 y /= z;
312 setDisplayPosition(x, y, newZoom);
313 }
314
315
316 /**
317 * Sets the displayed map pane and zoom level so that all map markers are
318 * visible.
319 */
320 public void setDisplayToFitMapMarkers() {
321 setDisplayToFitMapElements(true, false, false);
322 }
323
324 /**
325 * Sets the displayed map pane and zoom level so that all map rectangles are
326 * visible.
327 */
328 public void setDisplayToFitMapRectangles() {
329 setDisplayToFitMapElements(false, true, false);
330 }
331
332 /**
333 * Sets the displayed map pane and zoom level so that all map polygons are
334 * visible.
335 */
336 public void setDisplayToFitMapPolygons() {
337 setDisplayToFitMapElements(false, false, true);
338 }
339
340 /**
341 * @return the center
342 */
343 public Point getCenter() {
344 return center;
345 }
346
347 /**
348 * @param center the center to set
349 */
350 public void setCenter(Point center) {
351 this.center = center;
352 }
353
354 /**
355 * Calculates the latitude/longitude coordinate of the center of the
356 * currently displayed map area.
357 *
358 * @return latitude / longitude
359 */
360 public Coordinate getPosition() {
361 double lon = OsmMercator.XToLon(center.x, zoom);
362 double lat = OsmMercator.YToLat(center.y, zoom);
363 return new Coordinate(lat, lon);
364 }
365
366 /**
367 * Converts the relative pixel coordinate (regarding the top left corner of
368 * the displayed map) into a latitude / longitude coordinate
369 *
370 * @param mapPoint
371 * relative pixel coordinate regarding the top left corner of the
372 * displayed map
373 * @return latitude / longitude
374 */
375 public Coordinate getPosition(Point mapPoint) {
376 return getPosition(mapPoint.x, mapPoint.y);
377 }
378
379 /**
380 * Converts the relative pixel coordinate (regarding the top left corner of
381 * the displayed map) into a latitude / longitude coordinate
382 *
383 * @param mapPointX
384 * @param mapPointY
385 * @return latitude / longitude
386 */
387 public Coordinate getPosition(int mapPointX, int mapPointY) {
388 int x = center.x + mapPointX - getWidth() / 2;
389 int y = center.y + mapPointY - getHeight() / 2;
390 double lon = OsmMercator.XToLon(x, zoom);
391 double lat = OsmMercator.YToLat(y, zoom);
392 return new Coordinate(lat, lon);
393 }
394
395 /**
396 * Calculates the position on the map of a given coordinate
397 *
398 * @param lat
399 * @param lon
400 * @param checkOutside
401 * @return point on the map or <code>null</code> if the point is not visible
402 * and checkOutside set to <code>true</code>
403 */
404 public Point getMapPosition(double lat, double lon, boolean checkOutside) {
405 int x = OsmMercator.LonToX(lon, zoom);
406 int y = OsmMercator.LatToY(lat, zoom);
407 x -= center.x - getWidth() / 2;
408 y -= center.y - getHeight() / 2;
409 if (checkOutside) {
410 if (x < 0 || y < 0 || x > getWidth() || y > getHeight())
411 return null;
412 }
413 return new Point(x, y);
414 }
415
416 /**
417 * Calculates the position on the map of a given coordinate
418 *
419 * @param lat
420 * @param lon
421 * @return point on the map or <code>null</code> if the point is not visible
422 */
423 public Point getMapPosition(double lat, double lon) {
424 return getMapPosition(lat, lon, true);
425 }
426
427 /**
428 * Calculates the position on the map of a given coordinate
429 *
430 * @param coord
431 * @return point on the map or <code>null</code> if the point is not visible
432 */
433 public Point getMapPosition(Coordinate coord) {
434 if (coord != null)
435 return getMapPosition(coord.getLat(), coord.getLon());
436 else
437 return null;
438 }
439
440 /**
441 * Calculates the position on the map of a given coordinate
442 *
443 * @param coord
444 * @return point on the map or <code>null</code> if the point is not visible
445 * and checkOutside set to <code>true</code>
446 */
447 public Point getMapPosition(Coordinate coord, boolean checkOutside) {
448 if (coord != null)
449 return getMapPosition(coord.getLat(), coord.getLon(), checkOutside);
450 else
451 return null;
452 }
453
454 /**
455 * Gets the meter per pixel.
456 *
457 * @return the meter per pixel
458 * @author Jason Huntley
459 */
460 public double getMeterPerPixel() {
461 Point origin=new Point(5,5);
462 Point center=new Point(getWidth()/2, getHeight()/2);
463
464 double pDistance=center.distance(origin);
465
466 Coordinate originCoord=getPosition(origin);
467 Coordinate centerCoord=getPosition(center);
468
469 double mDistance=OsmMercator.getDistance(originCoord.getLat(), originCoord.getLon(),
470 centerCoord.getLat(), centerCoord.getLon());
471
472 return mDistance/pDistance;
473 }
474
475 @Override
476 protected void paintComponent(Graphics g) {
477 super.paintComponent(g);
478
479 int iMove = 0;
480
481 int tilesize = tileSource.getTileSize();
482 int tilex = center.x / tilesize;
483 int tiley = center.y / tilesize;
484 int off_x = (center.x % tilesize);
485 int off_y = (center.y % tilesize);
486
487 int w2 = getWidth() / 2;
488 int h2 = getHeight() / 2;
489 int posx = w2 - off_x;
490 int posy = h2 - off_y;
491
492 int diff_left = off_x;
493 int diff_right = tilesize - off_x;
494 int diff_top = off_y;
495 int diff_bottom = tilesize - off_y;
496
497 boolean start_left = diff_left < diff_right;
498 boolean start_top = diff_top < diff_bottom;
499
500 if (start_top) {
501 if (start_left) {
502 iMove = 2;
503 } else {
504 iMove = 3;
505 }
506 } else {
507 if (start_left) {
508 iMove = 1;
509 } else {
510 iMove = 0;
511 }
512 } // calculate the visibility borders
513 int x_min = -tilesize;
514 int y_min = -tilesize;
515 int x_max = getWidth();
516 int y_max = getHeight();
517
518 // paint the tiles in a spiral, starting from center of the map
519 boolean painted = true;
520 int x = 0;
521 while (painted) {
522 painted = false;
523 for (int i = 0; i < 4; i++) {
524 if (i % 2 == 0) {
525 x++;
526 }
527 for (int j = 0; j < x; j++) {
528 if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) {
529 // tile is visible
530 Tile tile = tileController.getTile(tilex, tiley, zoom);
531 if (tile != null) {
532 painted = true;
533 tile.paint(g, posx, posy);
534 if (tileGridVisible) {
535 g.drawRect(posx, posy, tilesize, tilesize);
536 }
537 }
538 }
539 Point p = move[iMove];
540 posx += p.x * tilesize;
541 posy += p.y * tilesize;
542 tilex += p.x;
543 tiley += p.y;
544 }
545 iMove = (iMove + 1) % move.length;
546 }
547 }
548 // outer border of the map
549 int mapSize = tilesize << zoom;
550 g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize);
551
552 // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20);
553
554 if (mapPolygonsVisible && mapPolygonList != null) {
555 for (MapPolygon polygon : mapPolygonList) {
556 paintPolygon(g, polygon);
557 }
558 }
559
560 if (mapRectanglesVisible && mapRectangleList != null) {
561 for (MapRectangle rectangle : mapRectangleList) {
562 paintRectangle(g, rectangle);
563 }
564 }
565
566 if (mapMarkersVisible && mapMarkerList != null) {
567 for (MapMarker marker : mapMarkerList) {
568 paintMarker(g, marker);
569 }
570 }
571
572 attribution.paintAttribution(g, getWidth(), getHeight(), getPosition(0, 0), getPosition(getWidth(), getHeight()), zoom, this);
573 }
574
575 /**
576 * Paint a single marker.
577 */
578 protected void paintMarker(Graphics g, MapMarker marker) {
579 Point p = getMapPosition(marker.getLat(), marker.getLon());
580 if (p != null) {
581 marker.paint(g, p);
582 }
583 }
584
585 /**
586 * Paint a single rectangle.
587 */
588 protected void paintRectangle(Graphics g, MapRectangle rectangle) {
589 Coordinate topLeft = rectangle.getTopLeft();
590 Coordinate bottomRight = rectangle.getBottomRight();
591 if (topLeft != null && bottomRight != null) {
592 Point pTopLeft = getMapPosition(topLeft, false);
593 Point pBottomRight = getMapPosition(bottomRight, false);
594 if (pTopLeft != null && pBottomRight != null) {
595 rectangle.paint(g, pTopLeft, pBottomRight);
596 }
597 }
598 }
599
600 /**
601 * Paint a single polygon.
602 */
603 protected void paintPolygon(Graphics g, MapPolygon polygon) {
604 List<Coordinate> coords = polygon.getPoints();
605 if (coords != null && coords.size() >= 3) {
606 List<Point> points = new LinkedList<Point>();
607 for (Coordinate c : coords) {
608 Point p = getMapPosition(c, false);
609 if (p == null) {
610 return;
611 }
612 points.add(p);
613 }
614 polygon.paint(g, points);
615 }
616 }
617
618 /**
619 * Moves the visible map pane.
620 *
621 * @param x
622 * horizontal movement in pixel.
623 * @param y
624 * vertical movement in pixel
625 */
626 public void moveMap(int x, int y) {
627 center.x += x;
628 center.y += y;
629 repaint();
630 this.fireJMVEvent(new JMVCommandEvent(COMMAND.MOVE, this));
631 }
632
633 /**
634 * @return the current zoom level
635 */
636 public int getZoom() {
637 return zoom;
638 }
639
640 /**
641 * Increases the current zoom level by one
642 */
643 public void zoomIn() {
644 setZoom(zoom + 1);
645 }
646
647 /**
648 * Increases the current zoom level by one
649 */
650 public void zoomIn(Point mapPoint) {
651 setZoom(zoom + 1, mapPoint);
652 }
653
654 /**
655 * Decreases the current zoom level by one
656 */
657 public void zoomOut() {
658 setZoom(zoom - 1);
659 }
660
661 /**
662 * Decreases the current zoom level by one
663 *
664 * @param mapPoint point to choose as center for new zoom level
665 */
666 public void zoomOut(Point mapPoint) {
667 setZoom(zoom - 1, mapPoint);
668 }
669
670 /**
671 * Set the zoom level and center point for display
672 *
673 * @param zoom new zoom level
674 * @param mapPoint point to choose as center for new zoom level
675 */
676 public void setZoom(int zoom, Point mapPoint) {
677 if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom()
678 || zoom == this.zoom)
679 return;
680 Coordinate zoomPos = getPosition(mapPoint);
681 tileController.cancelOutstandingJobs(); // Clearing outstanding load
682 // requests
683 setDisplayPositionByLatLon(mapPoint, zoomPos.getLat(), zoomPos.getLon(), zoom);
684
685 this.fireJMVEvent(new JMVCommandEvent(COMMAND.ZOOM, this));
686 }
687
688 /**
689 * Set the zoom level
690 *
691 * @param zoom new zoom level
692 */
693 public void setZoom(int zoom) {
694 setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2));
695 }
696
697 /**
698 * Every time the zoom level changes this method is called. Override it in
699 * derived implementations for adapting zoom dependent values. The new zoom
700 * level can be obtained via {@link #getZoom()}.
701 *
702 * @param oldZoom
703 * the previous zoom level
704 */
705 protected void zoomChanged(int oldZoom) {
706 zoomSlider.setToolTipText("Zoom level " + zoom);
707 zoomInButton.setToolTipText("Zoom to level " + (zoom + 1));
708 zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1));
709 zoomOutButton.setEnabled(zoom > tileController.getTileSource().getMinZoom());
710 zoomInButton.setEnabled(zoom < tileController.getTileSource().getMaxZoom());
711 }
712
713 public boolean isTileGridVisible() {
714 return tileGridVisible;
715 }
716
717 public void setTileGridVisible(boolean tileGridVisible) {
718 this.tileGridVisible = tileGridVisible;
719 repaint();
720 }
721
722 public boolean getMapMarkersVisible() {
723 return mapMarkersVisible;
724 }
725
726 /**
727 * Enables or disables painting of the {@link MapMarker}
728 *
729 * @param mapMarkersVisible
730 * @see #addMapMarker(MapMarker)
731 * @see #getMapMarkerList()
732 */
733 public void setMapMarkerVisible(boolean mapMarkersVisible) {
734 this.mapMarkersVisible = mapMarkersVisible;
735 repaint();
736 }
737
738 public void setMapMarkerList(List<MapMarker> mapMarkerList) {
739 this.mapMarkerList = mapMarkerList;
740 repaint();
741 }
742
743 public List<MapMarker> getMapMarkerList() {
744 return mapMarkerList;
745 }
746
747 public void setMapRectangleList(List<MapRectangle> mapRectangleList) {
748 this.mapRectangleList = mapRectangleList;
749 repaint();
750 }
751
752 public List<MapRectangle> getMapRectangleList() {
753 return mapRectangleList;
754 }
755
756 public void setMapPolygonList(List<MapPolygon> mapPolygonList) {
757 this.mapPolygonList = mapPolygonList;
758 repaint();
759 }
760
761 public List<MapPolygon> getMapPolygonList() {
762 return mapPolygonList;
763 }
764
765 public void addMapMarker(MapMarker marker) {
766 mapMarkerList.add(marker);
767 repaint();
768 }
769
770 public void removeMapMarker(MapMarker marker) {
771 mapMarkerList.remove(marker);
772 repaint();
773 }
774
775 public void removeAllMapMarkers() {
776 mapMarkerList.clear();
777 repaint();
778 }
779
780 public void addMapRectangle(MapRectangle rectangle) {
781 mapRectangleList.add(rectangle);
782 repaint();
783 }
784
785 public void removeMapRectangle(MapRectangle rectangle) {
786 mapRectangleList.remove(rectangle);
787 repaint();
788 }
789
790 public void removeAllMapRectangles() {
791 mapRectangleList.clear();
792 repaint();
793 }
794
795 public void addMapPolygon(MapPolygon polygon) {
796 mapPolygonList.add(polygon);
797 repaint();
798 }
799
800 public void removeMapPolygon(MapPolygon polygon) {
801 mapPolygonList.remove(polygon);
802 repaint();
803 }
804
805 public void removeAllMapPolygons() {
806 mapPolygonList.clear();
807 repaint();
808 }
809
810 public void setZoomContolsVisible(boolean visible) {
811 zoomSlider.setVisible(visible);
812 zoomInButton.setVisible(visible);
813 zoomOutButton.setVisible(visible);
814 }
815
816 public boolean getZoomContolsVisible() {
817 return zoomSlider.isVisible();
818 }
819
820 public void setTileSource(TileSource tileSource) {
821 if (tileSource.getMaxZoom() > MAX_ZOOM)
822 throw new RuntimeException("Maximum zoom level too high");
823 if (tileSource.getMinZoom() < MIN_ZOOM)
824 throw new RuntimeException("Minumim zoom level too low");
825 this.tileSource = tileSource;
826 tileController.setTileSource(tileSource);
827 zoomSlider.setMinimum(tileSource.getMinZoom());
828 zoomSlider.setMaximum(tileSource.getMaxZoom());
829 tileController.cancelOutstandingJobs();
830 if (zoom > tileSource.getMaxZoom()) {
831 setZoom(tileSource.getMaxZoom());
832 }
833
834 attribution.initialize(tileSource);
835 repaint();
836 }
837
838 public void tileLoadingFinished(Tile tile, boolean success) {
839 repaint();
840 }
841
842 public boolean isMapRectanglesVisible() {
843 return mapRectanglesVisible;
844 }
845
846 /**
847 * Enables or disables painting of the {@link MapRectangle}
848 *
849 * @param mapRectanglesVisible
850 * @see #addMapRectangle(MapRectangle)
851 * @see #getMapRectangleList()
852 */
853 public void setMapRectanglesVisible(boolean mapRectanglesVisible) {
854 this.mapRectanglesVisible = mapRectanglesVisible;
855 repaint();
856 }
857
858 public boolean isMapPolygonsVisible() {
859 return mapPolygonsVisible;
860 }
861
862 /**
863 * Enables or disables painting of the {@link MapPolygon}
864 *
865 * @param mapPolygonsVisible
866 * @see #addMapPolygon(MapPolygon)
867 * @see #getMapPolygonList()
868 */
869 public void setMapPolygonsVisible(boolean mapPolygonsVisible) {
870 this.mapPolygonsVisible = mapPolygonsVisible;
871 repaint();
872 }
873
874 /**
875 * Return tile information caching class
876 * @see TileLoaderListener#getTileCache()
877 */
878 public TileCache getTileCache() {
879 return tileController.getTileCache();
880 }
881
882 public void setTileLoader(TileLoader loader) {
883 tileController.setTileLoader(loader);
884 }
885
886 protected EventListenerList listenerList = new EventListenerList();
887
888 /**
889 * @param listener listener to set
890 */
891 public void addJMVListener(JMapViewerEventListener listener) {
892 listenerList.add(JMapViewerEventListener.class, listener);
893 }
894
895 /**
896 * @param listener listener to remove
897 */
898 public void removeJMVListener(JMapViewerEventListener listener) {
899 listenerList.remove(JMapViewerEventListener.class, listener);
900 }
901
902 /**
903 * Send an update to all objects registered with viewer
904 *
905 * @param event to dispatch
906 */
907 void fireJMVEvent(JMVCommandEvent evt) {
908 Object[] listeners = listenerList.getListenerList();
909 for (int i=0; i<listeners.length; i+=2) {
910 if (listeners[i]==JMapViewerEventListener.class) {
911 ((JMapViewerEventListener)listeners[i+1]).processCommand(evt);
912 }
913 }
914 }
915 }