gt: 		Insets insets = getInsets();
context: package com.opendoorlogistics.codefromweb.jxmapviewer2;
  
  import java.awt.Color;
  import java.awt.Cursor;
  import java.awt.Dimension;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Image;
  import java.awt.Insets;
  import java.awt.Point;
  import java.awt.Rectangle;
  import java.awt.event.MouseEvent;
  import java.awt.event.MouseWheelEvent;
  import java.awt.event.MouseWheelListener;
  import java.awt.geom.Point2D;
  import java.awt.geom.Rectangle2D;
  import java.awt.image.BufferedImage;
  import java.beans.DesignMode;
  import java.beans.PropertyChangeEvent;
  import java.beans.PropertyChangeListener;
  import java.net.URL;
  import java.util.Set;
  
  import javax.imageio.ImageIO;
  import javax.swing.JDesktopPane;
  import javax.swing.SwingUtilities;
  import javax.swing.event.MouseInputAdapter;
  
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.GeoPosition;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.Tile;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileFactory;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileFactoryInfo;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.TileListener;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.mapviewer.empty.EmptyTileFactory;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.AbstractPainter;
  import com.opendoorlogistics.codefromweb.jxmapviewer2.fork.swingx.painter.Painter;
  
  /**
   * A fork of the JxMapViewer class from the JxMapViewer2 project which extends
   * JDesktopPane instead of JPanel. This code is subject to the original
   * copyrights of the JxMapViewer2 project. Other modifications have also been
   * made.
   * 
   * The original JxMapViewer javadoc header follows:
   * 
   * A tile oriented map component that can easily be used with tile sources on
   * the web like Google and Yahoo maps, satellite data such as NASA imagery, and
   * also with file based sources like pre-processed NASA images. A known map
   * provider can be used with the SLMapServerInfo, which will connect to a 2km
   * resolution version of NASA's Blue Marble Next Generation imagery. @see
   * SLMapServerInfo for more information.
   * 
   * Note, the JXMapViewer has three center point properties. The
   * <B>addressLocation</B> property represents an abstract center of the map.
   * This would usually be something like the first item in a search result. It is
   * a {@link GeoPosition}. The <b>centerPosition</b> property represents the
   * current center point of the map. If the user pans the map then the
   * centerPosition point will change but the <B>addressLocation</B> will not.
   * Calling <B>recenterToAddressLocation()</B> will move the map back to that
   * center address. The <B>center</B> property represents the same point as the
   * centerPosition property, but as a Point2D in pixel space instead of a
   * GeoPosition in lat/long space. Note that the center property is a Point2D in
   * the entire world bitmap, not in the portion of the map currently visible. You
   * can use the <B>getViewportBounds()</B> method to find the portion of the map
   * currently visible and adjust your calculations accordingly. Changing the
   * <B>center</B> property will change the <B>centerPosition</B> property and
   * vice versa. All three properties are bound.
   * 
   * @author Joshua.Marinacci@sun.com
   * @see org.jdesktop.swingx.mapviewer.bmng.SLMapServerInfo
   */
  public class DesktopPaneMapViewer extends JDesktopPane implements DesignMode {
  	private static final long serialVersionUID = -3530746298586937321L;
  
  	/**
  	 * The zoom level. Generally a value between 1 and 15 (TODO Is this true for
  	 * all the mapping worlds? What does this mean if some mapping system
  	 * doesn't support the zoom level?
  	 */
  	private int zoomLevel = 1;
  
  	/**
  	 * The position, in <I>map coordinates</I> of the center point. This is
  	 * defined as the distance from the top and left edges of the map in pixels.
  	 * Dragging the map component will change the center position. Zooming
  	 * in/out will cause the center to be recalculated so as to remain in the
  	 * center of the new "map".
  	 */
  	private Point2D center = new Point2D.Double(0, 0);
  
  	/**
  	 * Indicates whether or not to draw the borders between tiles. Defaults to
  	 * false. TODO Generally not very nice looking, very much a product of
  	 * testing Consider whether this should really be a property or not.
  	 */
  	private boolean drawTileBorders = false;
  
  	/**
  	 * Factory used by this component to grab the tiles necessary for painting
  	 * the map.
  	 */
  	private TileFactory factory;
  
  	/**
  	 * The overlay to delegate to for painting the "foreground" of the map
  	 * component. This would include painting waypoints, day/night, etc. Also
  	 * receives mouse events.
  	 */
  	private Painter<? super DesktopPaneMapViewer> overlay;
  
  	private boolean designTime;
  
  	private Image loadingImage;
  
  	/**
  	 * Create a new JXMapViewer. By default it will use the EmptyTileFactory
  	 */
  	public DesktopPaneMapViewer() {
  		factory = new EmptyTileFactory();
  
  		// make a dummy loading image
  		try {
  			URL url = this.getClass().getResource("mapviewer/resources/loading.png");
  			this.setLoadingImage(ImageIO.read(url));
  		} catch (Throwable ex) {
  		//	System.out.println("could not load 'loading.png'");
  			BufferedImage img = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB);
  			Graphics2D g2 = img.createGraphics();
  			g2.setColor(Color.black);
  			g2.fillRect(0, 0, 16, 16);
  			g2.dispose();
  			this.setLoadingImage(img);
  		}
  
  	}
  	
  	@Override
  	protected void paintComponent(Graphics g) {
  		super.paintComponent(g);
  
  		doPaintComponent(g);
  	}
  
  	// the method that does the actual painting
  	private void doPaintComponent(Graphics g) {/*
  												 * if (isOpaque() ||
  												 * isDesignTime()) {
  												 * g.setColor(getBackground());
  												 * g.fillRect(0,0,getWidth(),
  												 * getHeight()); }
  												 */
  
  		if (isDesignTime()) {
  			// do nothing
  		} else {
  			int z = getZoom();
  			Rectangle viewportBounds = getViewportBounds();
  			drawMapTiles(g, z, viewportBounds);
  			drawOverlays(z, g, viewportBounds);
  		}
  
  		super.paintBorder(g);
  	}
  
  	/**
  	 * Indicate that the component is being used at design time, such as in a
  	 * visual editor like NetBeans' Matisse
  	 * 
  	 * @param b
  	 *            indicates if the component is being used at design time
  	 */
  	@Override
  	public void setDesignTime(boolean b) {
  		this.designTime = b;
  	}
  
  	/**
  	 * Indicates whether the component is being used at design time, such as in
  	 * a visual editor like NetBeans' Matisse
  	 * 
  	 * @return boolean indicating if the component is being used at design time
  	 */
  	@Override
  	public boolean isDesignTime() {
  		return designTime;
  	}
  
  	/**
  	 * Draw the map tiles. This method is for implementation use only.
  	 * 
  	 * @param g
  	 *            Graphics
  	 * @param zoom
  	 *            zoom level to draw at
  	 * @param viewportBounds
  	 *            the bounds to draw within
  	 */
  	protected void drawMapTiles(final Graphics g, final int zoom, Rectangle viewportBounds) {
  		int size = getTileFactory().getTileSize(zoom);
  		Dimension mapSize = getTileFactory().getMapSize(zoom);
  
  		// calculate the "visible" viewport area in tiles
  		int numWide = viewportBounds.width / size + 2;
  		int numHigh = viewportBounds.height / size + 2;
  
  		// TilePoint topLeftTile = getTileFactory().getTileCoordinate(
  		// new Point2D.Double(viewportBounds.x, viewportBounds.y));
  		TileFactoryInfo info = getTileFactory().getInfo();
  		int tpx = (int) Math.floor(viewportBounds.getX() / info.getTileSize(0));
  		int tpy = (int) Math.floor(viewportBounds.getY() / info.getTileSize(0));
  		// TilePoint topLeftTile = new TilePoint(tpx, tpy);
  
  		// p("top tile = " + topLeftTile);
  		// fetch the tiles from the factory and store them in the tiles cache
  		// attach the tileLoadListener
  		for (int x = 0; x <= numWide; x++) {
  			for (int y = 0; y <= numHigh; y++) {
  				int itpx = x + tpx;// topLeftTile.getX();
  				int itpy = y + tpy;// topLeftTile.getY();
  				// TilePoint point = new TilePoint(x + topLeftTile.getX(), y +
  				// topLeftTile.getY());
  				// only proceed if the specified tile point lies within the area
  				// being painted
  				if (g.getClipBounds().intersects(new Rectangle(itpx * size - viewportBounds.x, itpy * size - viewportBounds.y, size, size))) {
  					Tile tile = getTileFactory().getTile(itpx, itpy, zoom);
  					int ox = ((itpx * getTileFactory().getTileSize(zoom)) - viewportBounds.x);
  					int oy = ((itpy * getTileFactory().getTileSize(zoom)) - viewportBounds.y);
  
  					// if the tile is off the map to the north/south, then just
  					// don't paint anything
  					if (isTileOnMap(itpx, itpy, mapSize)) {
  						if (isOpaque()) {
  							g.setColor(getBackground());
  							g.fillRect(ox, oy, size, size);
  						}
  					} else if (tile.isLoaded()) {
  						g.drawImage(tile.getImage(), ox, oy, null);
  					} else {
  						// Use tile at higher zoom level with 200% magnification
  						Tile superTile = getTileFactory().getTile(itpx / 2, itpy / 2, zoom + 1);
  
  						if (superTile.isLoaded()) {
  							int offX = (itpx % 2) * size / 2;
  							int offY = (itpy % 2) * size / 2;
  							g.drawImage(superTile.getImage(), ox, oy, ox + size, oy + size, offX, offY, offX + size / 2, offY + size / 2, null);
  						} else {
  							int imageX = (getTileFactory().getTileSize(zoom) - getLoadingImage().getWidth(null)) / 2;
  							int imageY = (getTileFactory().getTileSize(zoom) - getLoadingImage().getHeight(null)) / 2;
  							g.setColor(Color.GRAY);
  							g.fillRect(ox, oy, size, size);
  							g.drawImage(getLoadingImage(), ox + imageX, oy + imageY, null);
  						}
  					}
  					if (isDrawTileBorders()) {
  
  						g.setColor(Color.black);
  						g.drawRect(ox, oy, size, size);
  						g.drawRect(ox + size / 2 - 5, oy + size / 2 - 5, 10, 10);
  						g.setColor(Color.white);
  						g.drawRect(ox + 1, oy + 1, size, size);
  
  						String text = itpx + ", " + itpy + ", " + getZoom();
  						g.setColor(Color.BLACK);
  						g.drawString(text, ox + 10, oy + 30);
  						g.drawString(text, ox + 10 + 2, oy + 30 + 2);
  						g.setColor(Color.WHITE);
  						g.drawString(text, ox + 10 + 1, oy + 30 + 1);
  					}
  				}
  			}
  		}
  	}
  
  	private void drawOverlays(final int zoom, final Graphics g, final Rectangle viewportBounds) {
  		if (overlay != null) {
  			overlay.paint((Graphics2D) g, this, getWidth(), getHeight());
  		}
  	}
  
  	private boolean isTileOnMap(int x, int y, Dimension mapSize) {
  		return  y >= mapSize.getHeight();
  	}
  
  	/**
  	 * Sets the map overlay. This is a Painter<JXMapViewer> which will paint on
  	 * top of the map. It can be used to draw waypoints, lines, or static
  	 * overlays like text messages.
  	 * 
  	 * @param overlay
  	 *            the map overlay to use
  	 */
  	public void setOverlayPainter(Painter<? super DesktopPaneMapViewer> overlay) {
  		Painter<? super DesktopPaneMapViewer> old = getOverlayPainter();
  		this.overlay = overlay;
  
  		PropertyChangeListener listener = new PropertyChangeListener() {
  			@Override
  			public void propertyChange(PropertyChangeEvent evt) {
  				if (evt.getNewValue().equals(Boolean.TRUE)) {
  					repaint();
  				}
  			}
  		};
  
  		if (old instanceof AbstractPainter) {
  			AbstractPainter<?> ap = (AbstractPainter<?>) overlay;
  			ap.removePropertyChangeListener("dirty", listener);
  		}
  
  		if (overlay instanceof AbstractPainter) {
  			AbstractPainter<?> ap = (AbstractPainter<?>) overlay;
  			ap.addPropertyChangeListener("dirty", listener);
  		}
  
  		firePropertyChange("mapOverlay", old, getOverlayPainter());
  		repaint();
  	}
  
  	/**
  	 * Gets the current map overlay
  	 * 
  	 * @return the current map overlay
  	 */
  	public Painter<? super DesktopPaneMapViewer> getOverlayPainter() {
  		return overlay;
  	}
  
  	/**
  	 * Returns the bounds of the viewport in pixels. This can be used to
  	 * transform points into the world bitmap coordinate space.
  	 * 
  	 * @return the bounds in <em>pixels</em> of the "view" of this map
  	 */
  	public Rectangle getViewportBounds() {
  		return calculateViewportBounds(getCenter());
  	}
  
  	private Rectangle calculateViewportBounds(Point2D centr) {
  