[jmapviewer] 03/13: Imported Upstream version 1.10+dfsg

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Fri Oct 9 09:40:53 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository jmapviewer.

commit 4fdb8d2e186233ed9139b22b78937e244615cc9b
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Fri Oct 9 10:37:53 2015 +0200

    Imported Upstream version 1.10+dfsg
---
 build.xml                                          |  48 ++++-
 .../gui/jmapviewer/AbstractLayer.java              |  51 +++--
 .../gui/jmapviewer/AttributionSupport.java         |   4 +-
 .../openstreetmap/gui/jmapviewer/Coordinate.java   |   8 +-
 .../gui/jmapviewer/DefaultMapController.java       |  25 ++-
 src/org/openstreetmap/gui/jmapviewer/Demo.java     |  60 +++---
 .../gui/jmapviewer/FeatureAdapter.java             |  22 ++-
 .../openstreetmap/gui/jmapviewer/JMapViewer.java   | 210 ++++++++++++---------
 .../gui/jmapviewer/JMapViewerTree.java             |  86 +++++----
 .../gui/jmapviewer/JobDispatcher.java              |  69 ++++---
 src/org/openstreetmap/gui/jmapviewer/Layer.java    |  23 ++-
 .../openstreetmap/gui/jmapviewer/LayerGroup.java   |  46 +++--
 .../gui/jmapviewer/MapMarkerCircle.java            |  90 +++++++--
 .../openstreetmap/gui/jmapviewer/MapMarkerDot.java |  10 +-
 .../gui/jmapviewer/MapObjectImpl.java              |  58 ++++--
 .../gui/jmapviewer/MapPolygonImpl.java             |  17 +-
 .../gui/jmapviewer/MapRectangleImpl.java           |  14 +-
 .../gui/jmapviewer/MemoryTileCache.java            |  49 +++--
 .../openstreetmap/gui/jmapviewer/OsmMercator.java  |  39 ++--
 .../gui/jmapviewer/OsmTileLoader.java              | 164 +++++++++-------
 src/org/openstreetmap/gui/jmapviewer/Style.java    |  21 ++-
 src/org/openstreetmap/gui/jmapviewer/Tile.java     | 141 ++++++++++----
 .../gui/jmapviewer/TileController.java             |   4 +-
 src/org/openstreetmap/gui/jmapviewer/TileXY.java   |  57 ++++++
 .../jmapviewer/checkBoxTree/CheckBoxNodeData.java  |  12 +-
 .../checkBoxTree/CheckBoxNodeEditor.java           |   9 +-
 .../jmapviewer/checkBoxTree/CheckBoxNodePanel.java |  12 +-
 .../checkBoxTree/CheckBoxNodeRenderer.java         |  56 +++---
 .../gui/jmapviewer/checkBoxTree/CheckBoxTree.java  | 148 +++++++++------
 .../gui/jmapviewer/interfaces/Attributed.java      |   4 +-
 .../jmapviewer/interfaces/CachedTileLoader.java    |   2 +-
 .../gui/jmapviewer/interfaces/ICoordinate.java     |  12 +-
 .../interfaces/JMapViewerEventListener.java        |   2 +-
 .../gui/jmapviewer/interfaces/MapMarker.java       |  26 ++-
 .../gui/jmapviewer/interfaces/MapObject.java       |  29 ++-
 .../gui/jmapviewer/interfaces/MapPolygon.java      |  20 +-
 .../gui/jmapviewer/interfaces/MapRectangle.java    |   6 +-
 .../jmapviewer/interfaces/TemplatedTileSource.java |  18 ++
 .../gui/jmapviewer/interfaces/TileCache.java       |   8 +-
 .../jmapviewer/interfaces/TileClearController.java |   2 +-
 .../gui/jmapviewer/interfaces/TileJob.java         |   4 +-
 .../gui/jmapviewer/interfaces/TileLoader.java      |   2 +-
 .../jmapviewer/interfaces/TileLoaderListener.java  |   2 +-
 .../gui/jmapviewer/interfaces/TileSource.java      | 175 +++++++++++++++--
 src/org/openstreetmap/gui/jmapviewer/package.html  |   2 +-
 .../tilesources/AbstractOsmTileSource.java         |   8 +-
 .../tilesources/AbstractTMSTileSource.java         | 158 ++++++++++++++--
 .../jmapviewer/tilesources/AbstractTileSource.java |   7 +-
 .../tilesources/BingAerialTileSource.java          |  51 +++--
 .../tilesources/MapQuestOpenAerialTileSource.java  |   4 +-
 .../tilesources/MapQuestOsmTileSource.java         |   6 +-
 .../gui/jmapviewer/tilesources/OsmTileSource.java  |  21 +--
 .../jmapviewer/tilesources/ScanexTileSource.java   | 109 ++++++-----
 .../tilesources/TemplatedTMSTileSource.java        |  87 +++++++--
 .../gui/jmapviewer/tilesources/TileSourceInfo.java |  79 +++++---
 55 files changed, 1622 insertions(+), 775 deletions(-)

diff --git a/build.xml b/build.xml
index 471058d..573115e 100644
--- a/build.xml
+++ b/build.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <project default="all" name="Compile and build java classes plus jar archives">
 
-	<target name="all" depends="clean,build,svn_info,pack,create_run_jar,create_release_zip,create_source_release_zip" />
+	<target name="all" depends="clean,build,svn_info,pack,create_run_jar,create_release_zip,create_source_release_zip,findbugs,checkstyle,javadoc" />
 
 	<target name="clean">
 		<mkdir dir="bin" />
@@ -33,7 +33,7 @@
         </exec>
     </target>
 	
-	<target name="pack">
+	<target name="pack" depends="build">
 		<!-- Create the JAR file containing the compiled class files -->
 		<jar destfile="JMapViewer.jar" filesetmanifest="mergewithoutmain">
 			<fileset dir="bin" includes="**/jmapviewer/**" />
@@ -75,4 +75,48 @@
 		</zip>
 	</target>
 
+    <target name="checkstyle">
+        <taskdef resource="com/puppycrawl/tools/checkstyle/ant/checkstyle-ant-task.properties" 
+        	classpath="tools/checkstyle/checkstyle-6.9-all.jar"/>
+        <checkstyle config="tools/checkstyle/jmapviewer_checks.xml">
+            <fileset dir="${basedir}/src" includes="**/*.java" />
+            <formatter type="xml" toFile="checkstyle-jmapviewer.xml"/>
+        </checkstyle>
+    </target>
+
+    <target name="findbugs" depends="pack">
+        <taskdef name="findbugs" classname="edu.umd.cs.findbugs.anttask.FindBugsTask" 
+        	classpath="tools/findbugs/findbugs-ant.jar"/>
+        <path id="findbugs-classpath">
+            <fileset dir="tools/findbugs/">
+                <include name="*.jar"/>
+            </fileset>
+        </path>
+        <property name="findbugs-classpath" refid="findbugs-classpath"/>
+        <findbugs output="xml"
+                outputFile="findbugs-jmapviewer.xml"
+                classpath="${findbugs-classpath}"
+                effort="max"
+                >
+            <sourcePath path="${basedir}/src" />
+            <class location="JMapViewer.jar" />
+        </findbugs>
+    </target>
+
+	<target name="javadoc">
+        <javadoc destdir="javadoc" 
+                sourcepath="src"
+                encoding="UTF-8"    
+                packagenames="org.openstreetmap.gui.jmapviewer.*"
+                windowtitle="JMapViewer"
+                use="true"
+                private="true"
+                linksource="true"
+                author="false">
+            <link href="http://docs.oracle.com/javase/7/docs/api"/>
+            <doctitle><![CDATA[<h2>JMapViewer - Javadoc</h2>]]></doctitle>
+            <bottom><![CDATA[<a href="https://josm.openstreetmap.de/">JMapViewer</a>]]></bottom>
+        </javadoc>
+    </target>
+
 </project>
diff --git a/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java b/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java
index cc79f22..3f56748 100644
--- a/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java
+++ b/src/org/openstreetmap/gui/jmapviewer/AbstractLayer.java
@@ -10,79 +10,100 @@ public class AbstractLayer {
     private String description;
     private Style style;
     private Boolean visible;
-    private Boolean visibleTexts=true;
+    private Boolean visibleTexts = Boolean.TRUE;
 
-    public AbstractLayer(String name){
-        this(name, (String)null);
+    public AbstractLayer(String name) {
+        this(name, (String) null);
     }
-    public AbstractLayer(String name, String description){
+
+    public AbstractLayer(String name, String description) {
         this(name, description, MapMarkerCircle.getDefaultStyle());
     }
-    public AbstractLayer(String name, Style style){
+
+    public AbstractLayer(String name, Style style) {
         this(name, null, style);
     }
-    public AbstractLayer(String name, String description, Style style){
+
+    public AbstractLayer(String name, String description, Style style) {
         this(null, name, description, style);
     }
-    public AbstractLayer(LayerGroup parent, String name){
+
+    public AbstractLayer(LayerGroup parent, String name) {
         this(parent, name, MapMarkerCircle.getDefaultStyle());
     }
-    public AbstractLayer(LayerGroup parent, String name, Style style){
+
+    public AbstractLayer(LayerGroup parent, String name, Style style) {
         this(parent, name, null, style);
     }
-    public AbstractLayer(LayerGroup parent, String name, String description, Style style){
+
+    public AbstractLayer(LayerGroup parent, String name, String description, Style style) {
         setParent(parent);
         setName(name);
         setDescription(description);
         setStyle(style);
-        setVisible(true);
+        setVisible(Boolean.TRUE);
 
-        if(parent!=null) parent.add(this);
+        if (parent != null) parent.add(this);
     }
+
     public LayerGroup getParent() {
         return parent;
     }
+
     public void setParent(LayerGroup parent) {
         this.parent = parent;
     }
+
     public String getName() {
         return name;
     }
+
     public void setName(String name) {
         this.name = name;
     }
+
     public String getDescription() {
         return description;
     }
+
     public void setDescription(String description) {
         this.description = description;
     }
+
     public Style getStyle() {
         return style;
     }
+
     public void setStyle(Style style) {
         this.style = style;
     }
+
     public Boolean isVisible() {
         return visible;
     }
+
     public void setVisible(Boolean visible) {
         this.visible = visible;
     }
+
     public static <E> List<E> add(List<E> list, E element) {
-        if(element!=null){
-            if(list==null) list = new ArrayList<>();
-            if(!list.contains(element)) list.add(element);
+        if (element != null) {
+            if (list == null) list = new ArrayList<>();
+            if (!list.contains(element)) list.add(element);
         }
         return list;
     }
+
     public Boolean isVisibleTexts() {
         return visibleTexts;
     }
+
     public void setVisibleTexts(Boolean visibleTexts) {
         this.visibleTexts = visibleTexts;
     }
-    public String toString(){
+
+    @Override
+    public String toString() {
         return name;
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java b/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
index cd53044..c398aa0 100644
--- a/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
+++ b/src/org/openstreetmap/gui/jmapviewer/AttributionSupport.java
@@ -15,6 +15,7 @@ import java.awt.image.ImageObserver;
 import java.util.HashMap;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.Attributed;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class AttributionSupport {
 
@@ -52,7 +53,8 @@ public class AttributionSupport {
         }
     }
 
-    public void paintAttribution(Graphics g, int width, int height, Coordinate topLeft, Coordinate bottomRight, int zoom, ImageObserver observer) {
+    public void paintAttribution(Graphics g, int width, int height, ICoordinate topLeft, ICoordinate bottomRight, 
+            int zoom, ImageObserver observer) {
         if (source == null || !source.requiresAttribution()) {
             attrToUBounds = null;
             attrImageBounds = null;
diff --git a/src/org/openstreetmap/gui/jmapviewer/Coordinate.java b/src/org/openstreetmap/gui/jmapviewer/Coordinate.java
index a4a9e97..b564726 100644
--- a/src/org/openstreetmap/gui/jmapviewer/Coordinate.java
+++ b/src/org/openstreetmap/gui/jmapviewer/Coordinate.java
@@ -5,7 +5,6 @@ import java.awt.geom.Point2D;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.Serializable;
 import java.util.Objects;
 
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
@@ -17,25 +16,29 @@ import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
  * @author Jan Peter Stotz
  *
  */
-public class Coordinate implements Serializable, ICoordinate {
+public class Coordinate implements ICoordinate {
     private transient Point2D.Double data;
 
     public Coordinate(double lat, double lon) {
         data = new Point2D.Double(lon, lat);
     }
 
+    @Override
     public double getLat() {
         return data.y;
     }
 
+    @Override
     public void setLat(double lat) {
         data.y = lat;
     }
 
+    @Override
     public double getLon() {
         return data.x;
     }
 
+    @Override
     public void setLon(double lon) {
         data.x = lon;
     }
@@ -51,6 +54,7 @@ public class Coordinate implements Serializable, ICoordinate {
         data.y = (Double) in.readObject();
     }
 
+    @Override
     public String toString() {
         return "Coordinate[" + data.y + ", " + data.x + "]";
     }
diff --git a/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java b/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
index 20c8c12..495184a 100644
--- a/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
+++ b/src/org/openstreetmap/gui/jmapviewer/DefaultMapController.java
@@ -22,9 +22,6 @@ MouseWheelListener {
     | MouseEvent.BUTTON2_DOWN_MASK;
 
     private static final int MAC_MOUSE_BUTTON3_MASK = MouseEvent.CTRL_DOWN_MASK | MouseEvent.BUTTON1_DOWN_MASK;
-    public DefaultMapController(JMapViewer map) {
-        super(map);
-    }
 
     private Point lastDragPoint;
 
@@ -38,11 +35,17 @@ MouseWheelListener {
     private boolean wheelZoomEnabled = true;
     private boolean doubleClickZoomEnabled = true;
 
+    public DefaultMapController(JMapViewer map) {
+        super(map);
+    }
+
+    @Override
     public void mouseDragged(MouseEvent e) {
         if (!movementEnabled || !isMoving)
             return;
         // Is only the selected mouse button pressed?
-        if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) {
+        if ((e.getModifiersEx() & MOUSE_BUTTONS_MASK) == movementMouseButtonMask 
+                || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) {
             Point p = e.getPoint();
             if (lastDragPoint != null) {
                 int diffx = lastDragPoint.x - p.x;
@@ -53,12 +56,14 @@ MouseWheelListener {
         }
     }
 
+    @Override
     public void mouseClicked(MouseEvent e) {
         if (doubleClickZoomEnabled && e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) {
             map.zoomIn(e.getPoint());
         }
     }
 
+    @Override
     public void mousePressed(MouseEvent e) {
         if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getModifiersEx() == MAC_MOUSE_BUTTON3_MASK) {
             lastDragPoint = null;
@@ -66,6 +71,7 @@ MouseWheelListener {
         }
     }
 
+    @Override
     public void mouseReleased(MouseEvent e) {
         if (e.getButton() == movementMouseButton || isPlatformOsx() && e.getButton() == MouseEvent.BUTTON1) {
             lastDragPoint = null;
@@ -73,6 +79,7 @@ MouseWheelListener {
         }
     }
 
+    @Override
     public void mouseWheelMoved(MouseWheelEvent e) {
         if (wheelZoomEnabled) {
             map.setZoom(map.getZoom() - e.getWheelRotation(), e.getPoint());
@@ -86,7 +93,7 @@ MouseWheelListener {
     /**
      * Enables or disables that the map pane can be moved using the mouse.
      *
-     * @param movementEnabled
+     * @param movementEnabled {@code true} to allow the map pane to be moved using the mouse
      */
     public void setMovementEnabled(boolean movementEnabled) {
         this.movementEnabled = movementEnabled;
@@ -97,15 +104,14 @@ MouseWheelListener {
     }
 
     /**
-     * Sets the mouse button that is used for moving the map. Possible values
-     * are:
+     * Sets the mouse button that is used for moving the map. Possible values are:
      * <ul>
      * <li>{@link MouseEvent#BUTTON1} (left mouse button)</li>
      * <li>{@link MouseEvent#BUTTON2} (middle mouse button)</li>
      * <li>{@link MouseEvent#BUTTON3} (right mouse button)</li>
      * </ul>
      *
-     * @param movementMouseButton
+     * @param movementMouseButton the mouse button that is used for moving the map
      */
     public void setMovementMouseButton(int movementMouseButton) {
         this.movementMouseButton = movementMouseButton;
@@ -140,12 +146,15 @@ MouseWheelListener {
         this.doubleClickZoomEnabled = doubleClickZoomEnabled;
     }
 
+    @Override
     public void mouseEntered(MouseEvent e) {
     }
 
+    @Override
     public void mouseExited(MouseEvent e) {
     }
 
+    @Override
     public void mouseMoved(MouseEvent e) {
         // Mac OSX simulates with  ctrl + mouse 1  the second mouse button hence no dragging events get fired.
         //
diff --git a/src/org/openstreetmap/gui/jmapviewer/Demo.java b/src/org/openstreetmap/gui/jmapviewer/Demo.java
index e86f42c..ea507b2 100644
--- a/src/org/openstreetmap/gui/jmapviewer/Demo.java
+++ b/src/org/openstreetmap/gui/jmapviewer/Demo.java
@@ -38,13 +38,13 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
 
     private static final long serialVersionUID = 1L;
 
-    private JMapViewerTree treeMap = null;
+    private final JMapViewerTree treeMap;
 
-    private JLabel zoomLabel=null;
-    private JLabel zoomValue=null;
+    private final JLabel zoomLabel;
+    private final JLabel zoomValue;
 
-    private JLabel mperpLabelName=null;
-    private JLabel mperpLabelValue = null;
+    private final JLabel mperpLabelName;
+    private final JLabel mperpLabelValue;
 
     /**
      * Constructs the {@code Demo}.
@@ -67,11 +67,11 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         JPanel panelBottom = new JPanel();
         JPanel helpPanel = new JPanel();
 
-        mperpLabelName=new JLabel("Meters/Pixels: ");
-        mperpLabelValue=new JLabel(String.format("%s",map().getMeterPerPixel()));
+        mperpLabelName = new JLabel("Meters/Pixels: ");
+        mperpLabelValue = new JLabel(String.format("%s", map().getMeterPerPixel()));
 
-        zoomLabel=new JLabel("Zoom: ");
-        zoomValue=new JLabel(String.format("%s", map().getZoom()));
+        zoomLabel = new JLabel("Zoom: ");
+        zoomValue = new JLabel(String.format("%s", map().getZoom()));
 
         add(panel, BorderLayout.NORTH);
         add(helpPanel, BorderLayout.SOUTH);
@@ -83,7 +83,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         helpPanel.add(helpLabel);
         JButton button = new JButton("setDisplayToFitMapMarkers");
         button.addActionListener(new ActionListener() {
-
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setDisplayToFitMapMarkers();
             }
@@ -95,13 +95,15 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
                 new MapQuestOsmTileSource(),
                 new MapQuestOpenAerialTileSource() });
         tileSourceSelector.addItemListener(new ItemListener() {
+            @Override
             public void itemStateChanged(ItemEvent e) {
                 map().setTileSource((TileSource) e.getItem());
             }
         });
         JComboBox<TileLoader> tileLoaderSelector;
-        tileLoaderSelector = new JComboBox<>(new TileLoader[] { new OsmTileLoader(map()) });
+        tileLoaderSelector = new JComboBox<>(new TileLoader[] {new OsmTileLoader(map())});
         tileLoaderSelector.addItemListener(new ItemListener() {
+            @Override
             public void itemStateChanged(ItemEvent e) {
                 map().setTileLoader((TileLoader) e.getItem());
             }
@@ -112,6 +114,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         final JCheckBox showMapMarker = new JCheckBox("Map markers visible");
         showMapMarker.setSelected(map().getMapMarkersVisible());
         showMapMarker.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setMapMarkerVisible(showMapMarker.isSelected());
             }
@@ -120,6 +123,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         ///
         final JCheckBox showTreeLayers = new JCheckBox("Tree Layers visible");
         showTreeLayers.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 treeMap.setTreeVisible(showTreeLayers.isSelected());
             }
@@ -128,6 +132,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         ///
         final JCheckBox showToolTip = new JCheckBox("ToolTip visible");
         showToolTip.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setToolTipText(null);
             }
@@ -137,6 +142,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         final JCheckBox showTileGrid = new JCheckBox("Tile grid visible");
         showTileGrid.setSelected(map().isTileGridVisible());
         showTileGrid.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setTileGridVisible(showTileGrid.isSelected());
             }
@@ -145,6 +151,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         final JCheckBox showZoomControls = new JCheckBox("Show zoom controls");
         showZoomControls.setSelected(map().getZoomControlsVisible());
         showZoomControls.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setZoomContolsVisible(showZoomControls.isSelected());
             }
@@ -152,6 +159,7 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         panelBottom.add(showZoomControls);
         final JCheckBox scrollWrapEnabled = new JCheckBox("Scrollwrap enabled");
         scrollWrapEnabled.addActionListener(new ActionListener() {
+            @Override
             public void actionPerformed(ActionEvent e) {
                 map().setScrollWrapEnabled(scrollWrapEnabled.isSelected());
             }
@@ -186,17 +194,17 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
         treeMap.addLayer(germanyWestLayer);
         treeMap.addLayer(germanyEastLayer);
 
-        MapPolygon bermudas = new MapPolygonImpl(c(49,1), c(45,10), c(40,5));
-        map().addMapPolygon( bermudas );
-        map().addMapPolygon( new MapPolygonImpl(germanyEastLayer, "Riedstadt", ebersheim, darmstadt, eberstadt, empty));
+        MapPolygon bermudas = new MapPolygonImpl(c(49, 1), c(45, 10), c(40, 5));
+        map().addMapPolygon(bermudas);
+        map().addMapPolygon(new MapPolygonImpl(germanyEastLayer, "Riedstadt", ebersheim, darmstadt, eberstadt, empty));
 
         map().addMapMarker(new MapMarkerCircle(germanyWestLayer, "North of Suisse", new Coordinate(48, 7), .5));
         Layer spain = treeMap.addLayer("Spain");
         map().addMapMarker(new MapMarkerCircle(spain, "La Garena", new Coordinate(40.4838, -3.39), .002));
-        spain.setVisible(false);
+        spain.setVisible(Boolean.FALSE);
 
         Layer wales = treeMap.addLayer("UK");
-        map().addMapRectangle(new MapRectangleImpl(wales, "Wales", c(53.35,-4.57), c(51.64,-2.63)));
+        map().addMapRectangle(new MapRectangleImpl(wales, "Wales", c(53.35, -4.57), c(51.64, -2.63)));
 
         // map.setDisplayPosition(new Coordinate(49.807, 8.6), 11);
         // map.setTileGridVisible(true);
@@ -220,31 +228,30 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
                 } else {
                     map().setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                 }
-                if(showToolTip.isSelected()) map().setToolTipText(map().getPosition(p).toString());
+                if (showToolTip.isSelected()) map().setToolTipText(map().getPosition(p).toString());
             }
         });
     }
-    private JMapViewer map(){
+
+    private JMapViewer map() {
         return treeMap.getViewer();
     }
-    private static Coordinate c(double lat, double lon){
+
+    private static Coordinate c(double lat, double lon) {
         return new Coordinate(lat, lon);
     }
 
     /**
-     * @param args
+     * @param args Main program arguments
      */
     public static void main(String[] args) {
-        // java.util.Properties systemProperties = System.getProperties();
-        // systemProperties.setProperty("http.proxyHost", "localhost");
-        // systemProperties.setProperty("http.proxyPort", "8008");
         new Demo().setVisible(true);
     }
 
     private void updateZoomParameters() {
-        if (mperpLabelValue!=null)
-            mperpLabelValue.setText(String.format("%s",map().getMeterPerPixel()));
-        if (zoomValue!=null)
+        if (mperpLabelValue != null)
+            mperpLabelValue.setText(String.format("%s", map().getMeterPerPixel()));
+        if (zoomValue != null)
             zoomValue.setText(String.format("%s", map().getZoom()));
     }
 
@@ -255,5 +262,4 @@ public class Demo extends JFrame implements JMapViewerEventListener  {
             updateZoomParameters();
         }
     }
-
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java b/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
index c048e44..f8f0f67 100644
--- a/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
+++ b/src/org/openstreetmap/gui/jmapviewer/FeatureAdapter.java
@@ -8,25 +8,29 @@ import java.net.URISyntaxException;
 import java.text.MessageFormat;
 import java.util.logging.Logger;
 
-public class FeatureAdapter {
+public final class FeatureAdapter {
 
-    public static interface BrowserAdapter {
+    private static BrowserAdapter browserAdapter = new DefaultBrowserAdapter();
+    private static TranslationAdapter translationAdapter = new DefaultTranslationAdapter();
+    private static LoggingAdapter loggingAdapter = new DefaultLoggingAdapter();
+
+    private FeatureAdapter() {
+        // private constructor for utility classes
+    }
+
+    public interface BrowserAdapter {
         void openLink(String url);
     }
 
-    public static interface TranslationAdapter {
+    public interface TranslationAdapter {
         String tr(String text, Object... objects);
         // TODO: more i18n functions
     }
 
-    public static interface LoggingAdapter {
+    public interface LoggingAdapter {
         Logger getLogger(String name);
     }
 
-    private static BrowserAdapter browserAdapter = new DefaultBrowserAdapter();
-    private static TranslationAdapter translationAdapter = new DefaultTranslationAdapter();
-    private static LoggingAdapter loggingAdapter = new DefaultLoggingAdapter();
-
     public static void registerBrowserAdapter(BrowserAdapter browserAdapter) {
         FeatureAdapter.browserAdapter = browserAdapter;
     }
@@ -46,7 +50,7 @@ public class FeatureAdapter {
     public static String tr(String text, Object... objects) {
         return translationAdapter.tr(text, objects);
     }
-    
+
     public static Logger getLogger(String name) {
         return loggingAdapter.getLogger(name);
     }
diff --git a/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java b/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
index e70ca00..b3d1fc5 100644
--- a/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
+++ b/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
@@ -39,7 +39,7 @@ import org.openstreetmap.gui.jmapviewer.tilesources.OsmTileSource;
  * OpenStreetMap project.
  *
  * @author Jan Peter Stotz
- *
+ * @author Jason Huntley
  */
 public class JMapViewer extends JPanel implements TileLoaderListener {
 
@@ -48,14 +48,14 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Vectors for clock-wise tile painting
      */
-    protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) };
+    private static final Point[] move = {new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1)};
 
     public static final int MAX_ZOOM = 22;
     public static final int MIN_ZOOM = 0;
 
-    protected List<MapMarker> mapMarkerList;
-    protected List<MapRectangle> mapRectangleList;
-    protected List<MapPolygon> mapPolygonList;
+    protected transient List<MapMarker> mapMarkerList;
+    protected transient List<MapRectangle> mapRectangleList;
+    protected transient List<MapPolygon> mapPolygonList;
 
     protected boolean mapMarkersVisible;
     protected boolean mapRectanglesVisible;
@@ -64,7 +64,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     protected boolean tileGridVisible;
     protected boolean scrollWrapEnabled;
 
-    protected TileController tileController;
+    protected transient TileController tileController;
 
     /**
      * x- and y-position of the center of this map-panel on the world map
@@ -88,9 +88,11 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     protected ZOOM_BUTTON_STYLE zoomButtonStyle;
 
-    protected TileSource tileSource;
+    protected transient TileSource tileSource;
+
+    protected transient AttributionSupport attribution = new AttributionSupport();
 
-    protected AttributionSupport attribution = new AttributionSupport();
+    protected EventListenerList evtListenerList = new EventListenerList();
 
     /**
      * Creates a standard {@link JMapViewer} instance that can be controlled via
@@ -138,6 +140,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         zoomSlider.setBounds(10, 10, 30, 150);
         zoomSlider.setOpaque(false);
         zoomSlider.addChangeListener(new ChangeListener() {
+            @Override
             public void stateChanged(ChangeEvent e) {
                 setZoom(zoomSlider.getValue());
             }
@@ -156,6 +159,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         zoomInButton.setBounds(4, 155, size, size);
         zoomInButton.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent e) {
                 zoomIn();
             }
@@ -173,6 +177,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         zoomOutButton.setBounds(8 + size, 155, size, size);
         zoomOutButton.addActionListener(new ActionListener() {
 
+            @Override
             public void actionPerformed(ActionEvent e) {
                 zoomOut();
             }
@@ -190,7 +195,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      * @param zoom
      *            {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM}
      */
-    public void setDisplayPosition(Coordinate to, int zoom) {
+    public void setDisplayPosition(ICoordinate to, int zoom) {
         setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), to, zoom);
     }
 
@@ -208,10 +213,9 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      *            {@link #MIN_ZOOM} <= zoom level <=
      *            {@link TileSource#getMaxZoom()}
      */
-    public void setDisplayPosition(Point mapPoint, Coordinate to, int zoom) {
-        int x = tileSource.LonToX(to.getLon(), zoom);
-        int y = tileSource.LatToY(to.getLat(), zoom);
-        setDisplayPosition(mapPoint, x, y, zoom);
+    public void setDisplayPosition(Point mapPoint, ICoordinate to, int zoom) {
+        Point p = tileSource.latLonToXY(to, zoom);
+        setDisplayPosition(mapPoint, p.x, p.y, zoom);
     }
 
     public void setDisplayPosition(int x, int y, int zoom) {
@@ -245,6 +249,9 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     /**
      * Sets the displayed map pane and zoom level so that all chosen map elements are visible.
+     * @param markers whether to consider markers
+     * @param rectangles whether to consider rectangles
+     * @param polygons whether to consider polygons
      */
     public void setDisplayToFitMapElements(boolean markers, boolean rectangles, boolean polygons) {
         int nbElemToCheck = 0;
@@ -257,51 +264,51 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         if (nbElemToCheck == 0)
             return;
 
-        int x_min = Integer.MAX_VALUE;
-        int y_min = Integer.MAX_VALUE;
-        int x_max = Integer.MIN_VALUE;
-        int y_max = Integer.MIN_VALUE;
+        int xMin = Integer.MAX_VALUE;
+        int yMin = Integer.MAX_VALUE;
+        int xMax = Integer.MIN_VALUE;
+        int yMax = Integer.MIN_VALUE;
         int mapZoomMax = tileController.getTileSource().getMaxZoom();
 
-        if (markers) {
+        if (markers && mapMarkerList != null) {
             synchronized (mapMarkerList) {
                 for (MapMarker marker : mapMarkerList) {
                     if (marker.isVisible()) {
-                        int x = tileSource.LonToX(marker.getLon(), mapZoomMax);
-                        int y = tileSource.LatToY(marker.getLat(), mapZoomMax);
-                        x_max = Math.max(x_max, x);
-                        y_max = Math.max(y_max, y);
-                        x_min = Math.min(x_min, x);
-                        y_min = Math.min(y_min, y);
+                        Point p = tileSource.latLonToXY(marker.getCoordinate(), mapZoomMax);
+                        xMax = Math.max(xMax, p.x);
+                        yMax = Math.max(yMax, p.y);
+                        xMin = Math.min(xMin, p.x);
+                        yMin = Math.min(yMin, p.y);
                     }
                 }
             }
         }
 
-        if (rectangles) {
+        if (rectangles && mapRectangleList != null) {
             synchronized (mapRectangleList) {
                 for (MapRectangle rectangle : mapRectangleList) {
                     if (rectangle.isVisible()) {
-                        x_max = Math.max(x_max, tileSource.LonToX(rectangle.getBottomRight().getLon(), mapZoomMax));
-                        y_max = Math.max(y_max, tileSource.LatToY(rectangle.getTopLeft().getLat(), mapZoomMax));
-                        x_min = Math.min(x_min, tileSource.LonToX(rectangle.getTopLeft().getLon(), mapZoomMax));
-                        y_min = Math.min(y_min, tileSource.LatToY(rectangle.getBottomRight().getLat(), mapZoomMax));
+                        Point bottomRight = tileSource.latLonToXY(rectangle.getBottomRight(), mapZoomMax);
+                        Point topLeft = tileSource.latLonToXY(rectangle.getTopLeft(), mapZoomMax);
+                        xMax = Math.max(xMax, bottomRight.x);
+                        yMax = Math.max(yMax, topLeft.y);
+                        xMin = Math.min(xMin, topLeft.x);
+                        yMin = Math.min(yMin, bottomRight.y);
                     }
                 }
             }
         }
 
-        if (polygons) {
+        if (polygons && mapPolygonList != null) {
             synchronized (mapPolygonList) {
                 for (MapPolygon polygon : mapPolygonList) {
                     if (polygon.isVisible()) {
                         for (ICoordinate c : polygon.getPoints()) {
-                            int x = tileSource.LonToX(c.getLon(), mapZoomMax);
-                            int y = tileSource.LatToY(c.getLat(), mapZoomMax);
-                            x_max = Math.max(x_max, x);
-                            y_max = Math.max(y_max, y);
-                            x_min = Math.min(x_min, x);
-                            y_min = Math.min(y_min, y);
+                            Point p = tileSource.latLonToXY(c, mapZoomMax);
+                            xMax = Math.max(xMax, p.x);
+                            yMax = Math.max(yMax, p.y);
+                            xMin = Math.min(xMin, p.x);
+                            yMin = Math.min(yMin, p.y);
                         }
                     }
                 }
@@ -311,15 +318,15 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         int height = Math.max(0, getHeight());
         int width = Math.max(0, getWidth());
         int newZoom = mapZoomMax;
-        int x = x_max - x_min;
-        int y = y_max - y_min;
+        int x = xMax - xMin;
+        int y = yMax - yMin;
         while (x > width || y > height) {
             newZoom--;
             x >>= 1;
             y >>= 1;
         }
-        x = x_min + (x_max - x_min) / 2;
-        y = y_min + (y_max - y_min) / 2;
+        x = xMin + (xMax - xMin) / 2;
+        y = yMin + (yMax - yMin) / 2;
         int z = 1 << (mapZoomMax - newZoom);
         x /= z;
         y /= z;
@@ -367,10 +374,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      *
      * @return latitude / longitude
      */
-    public Coordinate getPosition() {
-        double lon = tileSource.XToLon(center.x, zoom);
-        double lat = tileSource.YToLat(center.y, zoom);
-        return new Coordinate(lat, lon);
+    public ICoordinate getPosition() {
+        return tileSource.xyToLatLon(center, zoom);
     }
 
     /**
@@ -382,7 +387,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      *            displayed map
      * @return latitude / longitude
      */
-    public Coordinate getPosition(Point mapPoint) {
+    public ICoordinate getPosition(Point mapPoint) {
         return getPosition(mapPoint.x, mapPoint.y);
     }
 
@@ -390,53 +395,60 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      * Converts the relative pixel coordinate (regarding the top left corner of
      * the displayed map) into a latitude / longitude coordinate
      *
-     * @param mapPointX
-     * @param mapPointY
+     * @param mapPointX X coordinate
+     * @param mapPointY Y coordinate
      * @return latitude / longitude
      */
-    public Coordinate getPosition(int mapPointX, int mapPointY) {
+    public ICoordinate getPosition(int mapPointX, int mapPointY) {
         int x = center.x + mapPointX - getWidth() / 2;
         int y = center.y + mapPointY - getHeight() / 2;
-        double lon = tileSource.XToLon(x, zoom);
-        double lat = tileSource.YToLat(y, zoom);
-        return new Coordinate(lat, lon);
+        return tileSource.xyToLatLon(x, y, zoom);
     }
 
     /**
      * Calculates the position on the map of a given coordinate
      *
-     * @param lat
-     * @param lon
-     * @param checkOutside
+     * @param lat latitude
+     * @param lon longitude
+     * @param checkOutside check if the point is outside the displayed area
      * @return point on the map or <code>null</code> if the point is not visible
      *         and checkOutside set to <code>true</code>
      */
     public Point getMapPosition(double lat, double lon, boolean checkOutside) {
-        int x = tileSource.LonToX(lon, zoom);
-        int y = tileSource.LatToY(lat, zoom);
-        x -= center.x - getWidth() / 2;
-        y -= center.y - getHeight() / 2;
-        if (checkOutside) {
-            if (x < 0 || y < 0 || x > getWidth() || y > getHeight())
-                return null;
+        Point p = tileSource.latLonToXY(lat, lon, zoom);
+        p.translate(-(center.x - getWidth() / 2), -(center.y - getHeight() /2));
+
+        if (checkOutside && (p.x < 0 || p.y < 0 || p.x > getWidth() || p.y > getHeight())) {
+            return null;
         }
-        return new Point(x, y);
+        return p;
+    }
+
+    /**
+     * Calculates the position on the map of a given coordinate
+     *
+     * @param lat latitude
+     * @param lon longitude
+     * @return point on the map or <code>null</code> if the point is not visible
+     */
+    public Point getMapPosition(double lat, double lon) {
+        return getMapPosition(lat, lon, true);
     }
 
     /**
      * Calculates the position on the map of a given coordinate
      *
      * @param lat Latitude
+     * @param lon longitude
      * @param offset Offset respect Latitude
-     * @param checkOutside
+     * @param checkOutside check if the point is outside the displayed area
      * @return Integer the radius in pixels
      */
-    public Integer getLatOffset(double lat, double offset, boolean checkOutside) {
-        int y = tileSource.LatToY(lat + offset, zoom);
-        y -= center.y - getHeight() / 2;
-        if (checkOutside) {
-            if (y < 0 || y > getHeight())
-                return null;
+    public Integer getLatOffset(double lat, double lon, double offset, boolean checkOutside) {
+        Point p = tileSource.latLonToXY(lat, lon, zoom);
+        int y = p.y - center.y - getHeight() / 2;
+        if (checkOutside && (y < 0 || y > getHeight())) {
+            return null;
         }
         return y;
     }
@@ -444,25 +456,34 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Calculates the position on the map of a given coordinate
      *
-     * @param lat
-     * @param lon
-     * @return point on the map or <code>null</code> if the point is not visible
+     * @param lat Latitude
+     * @param offset Offset respect Latitude
+     * @param checkOutside check if the point is outside the displayed area
+     * @return Integer the radius in pixels
+     * @deprecated use {@link #getLatOffset(double, double, double, boolean)}
      */
-    public Point getMapPosition(double lat, double lon) {
-        return getMapPosition(lat, lon, true);
+    @Deprecated
+    public Integer getLatOffset(double lat, double offset, boolean checkOutside) {
+        int y = tileSource.latToY(lat + offset, zoom);
+        y -= center.y - getHeight() / 2;
+        if (checkOutside && (y < 0 || y > getHeight())) {
+            return null;
+        }
+        return y;
     }
 
     /**
      * Calculates the position on the map of a given coordinate
      *
      * @param marker MapMarker object that define the x,y coordinate
+     * @param p coordinate
      * @return Integer the radius in pixels
      */
     public Integer getRadius(MapMarker marker, Point p) {
         if (marker.getMarkerStyle() == MapMarker.STYLE.FIXED)
             return (int) marker.getRadius();
         else if (p != null) {
-            Integer radius = getLatOffset(marker.getLat(), marker.getRadius(), false);
+            Integer radius = getLatOffset(marker.getLat(), marker.getLon(), marker.getRadius(), false);
             radius = radius == null ? null : p.y - radius.intValue();
             return radius;
         } else
@@ -472,7 +493,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Calculates the position on the map of a given coordinate
      *
-     * @param coord
+     * @param coord coordinate
      * @return point on the map or <code>null</code> if the point is not visible
      */
     public Point getMapPosition(Coordinate coord) {
@@ -485,7 +506,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Calculates the position on the map of a given coordinate
      *
-     * @param coord
+     * @param coord coordinate
+     * @param checkOutside check if the point is outside the displayed area
      * @return point on the map or <code>null</code> if the point is not visible
      *         and checkOutside set to <code>true</code>
      */
@@ -500,7 +522,6 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      * Gets the meter per pixel.
      *
      * @return the meter per pixel
-     * @author Jason Huntley
      */
     public double getMeterPerPixel() {
         Point origin = new Point(5, 5);
@@ -508,8 +529,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
         double pDistance = center.distance(origin);
 
-        Coordinate originCoord = getPosition(origin);
-        Coordinate centerCoord = getPosition(center);
+        ICoordinate originCoord = getPosition(origin);
+        ICoordinate centerCoord = getPosition(center);
 
         double mDistance = tileSource.getDistance(originCoord.getLat(), originCoord.getLon(),
                 centerCoord.getLat(), centerCoord.getLon());
@@ -526,8 +547,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         int tilesize = tileSource.getTileSize();
         int tilex = center.x / tilesize;
         int tiley = center.y / tilesize;
-        int off_x = (center.x % tilesize);
-        int off_y = (center.y % tilesize);
+        int off_x = center.x % tilesize;
+        int off_y = center.y % tilesize;
 
         int w2 = getWidth() / 2;
         int h2 = getHeight() / 2;
@@ -578,7 +599,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
                         Tile tile;
                         if (scrollWrapEnabled) {
                             // in case tilex is out of bounds, grab the tile to use for wrapping
-                            int tilexWrap = (((tilex % gridLength) + gridLength) % gridLength);
+                            int tilexWrap = ((tilex % gridLength) + gridLength) % gridLength;
                             tile = tileController.getTile(tilexWrap, tiley, zoom);
                         } else {
                             tile = tileController.getTile(tilex, tiley, zoom);
@@ -648,6 +669,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     /**
      * Paint a single marker.
+     * @param g Graphics used for painting
+     * @param marker marker to paint
      */
     protected void paintMarker(Graphics g, MapMarker marker) {
         Point p = getMapPosition(marker.getLat(), marker.getLon(), marker.getMarkerStyle() == MapMarker.STYLE.FIXED);
@@ -681,6 +704,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     /**
      * Paint a single rectangle.
+     * @param g Graphics used for painting
+     * @param rectangle rectangle to paint
      */
     protected void paintRectangle(Graphics g, MapRectangle rectangle) {
         Coordinate topLeft = rectangle.getTopLeft();
@@ -711,7 +736,6 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
                         pBottomRight.x = xBottomRightWrap;
                         rectangle.paint(g, pTopLeft, pBottomRight);
                     }
-
                 }
             }
         }
@@ -719,6 +743,8 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     /**
      * Paint a single polygon.
+     * @param g Graphics used for painting
+     * @param polygon polygon to paint
      */
     protected void paintPolygon(Graphics g, MapPolygon polygon) {
         List<? extends ICoordinate> coords = polygon.getPoints();
@@ -825,7 +851,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         if (zoom > tileController.getTileSource().getMaxZoom() || zoom < tileController.getTileSource().getMinZoom()
                 || zoom == this.zoom)
             return;
-        Coordinate zoomPos = getPosition(mapPoint);
+        ICoordinate zoomPos = getPosition(mapPoint);
         tileController.cancelOutstandingJobs(); // Clearing outstanding load
         // requests
         setDisplayPosition(mapPoint, zoomPos, zoom);
@@ -874,7 +900,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Enables or disables painting of the {@link MapMarker}
      *
-     * @param mapMarkersVisible
+     * @param mapMarkersVisible {@code true} to enable painting of markers
      * @see #addMapMarker(MapMarker)
      * @see #getMapMarkerList()
      */
@@ -970,7 +996,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
             throw new RuntimeException("Maximum zoom level too high");
         if (tileSource.getMinZoom() < MIN_ZOOM)
             throw new RuntimeException("Minimum zoom level too low");
-        Coordinate position = getPosition();
+        ICoordinate position = getPosition();
         this.tileSource = tileSource;
         tileController.setTileSource(tileSource);
         zoomSlider.setMinimum(tileSource.getMinZoom());
@@ -984,6 +1010,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         repaint();
     }
 
+    @Override
     public void tileLoadingFinished(Tile tile, boolean success) {
         tile.setLoaded(success);
         repaint();
@@ -996,7 +1023,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Enables or disables painting of the {@link MapRectangle}
      *
-     * @param mapRectanglesVisible
+     * @param mapRectanglesVisible {@code true} to enable painting of rectangles
      * @see #addMapRectangle(MapRectangle)
      * @see #getMapRectangleList()
      */
@@ -1012,7 +1039,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
     /**
      * Enables or disables painting of the {@link MapPolygon}
      *
-     * @param mapPolygonsVisible
+     * @param mapPolygonsVisible {@code true} to enable painting of polygons
      * @see #addMapPolygon(MapPolygon)
      * @see #getMapPolygonList()
      */
@@ -1065,6 +1092,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
 
     /**
      * Return tile information caching class
+     * @return tile cache
      * @see TileController#getTileCache()
      */
     public TileCache getTileCache() {
@@ -1079,8 +1107,6 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
         return attribution;
     }
 
-    protected EventListenerList evtListenerList = new EventListenerList();
-
     /**
      * @param listener listener to set
      */
@@ -1100,7 +1126,7 @@ public class JMapViewer extends JPanel implements TileLoaderListener {
      *
      * @param evt event to dispatch
      */
-    void fireJMVEvent(JMVCommandEvent evt) {
+    private void fireJMVEvent(JMVCommandEvent evt) {
         Object[] listeners = evtListenerList.getListenerList();
         for (int i = 0; i < listeners.length; i += 2) {
             if (listeners[i] == JMapViewerEventListener.class) {
diff --git a/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java b/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java
index 472a620..5979957 100644
--- a/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java
+++ b/src/org/openstreetmap/gui/jmapviewer/JMapViewerTree.java
@@ -34,13 +34,14 @@ public class JMapViewerTree extends JPanel{
     private JPanel treePanel;
     private JSplitPane splitPane;
 
-    public JMapViewerTree(String name){
+    public JMapViewerTree(String name) {
         this(name, false);
     }
-    public JMapViewerTree(String name, boolean treeVisible){
+
+    public JMapViewerTree(String name, boolean treeVisible) {
         super();
         splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
-        
+
         tree = new CheckBoxTree(name);
         treePanel = new JPanel();
         treePanel.setLayout(new BorderLayout());
@@ -50,7 +51,7 @@ public class JMapViewerTree extends JPanel{
 
         splitPane.setOneTouchExpandable(true);
         splitPane.setDividerLocation(150);
-        
+
         //Provide minimum sizes for the two components in the split pane
         Dimension minimumSize = new Dimension(100, 50);
         //tree.setMinimumSize(minimumSize);
@@ -59,41 +60,45 @@ public class JMapViewerTree extends JPanel{
         setLayout(new BorderLayout());
         setTreeVisible(treeVisible);
         tree.addNodeListener(new MouseAdapter() {
+            @Override
             public void mousePressed(MouseEvent e) {
                 maybeShowPopup(e);
             }
+
+            @Override
             public void mouseReleased(MouseEvent e) {
                 maybeShowPopup(e);
             }
+
             private void maybeShowPopup(MouseEvent e) {
                 if (e.isPopupTrigger()) {
-                    e.getSource();
-                    AbstractLayer layer = ((CheckBoxNodePanel)e.getComponent()).getData().getAbstractLayer();
-                    if(layer!=null)
+                    AbstractLayer layer = ((CheckBoxNodePanel) e.getComponent()).getData().getAbstractLayer();
+                    if (layer != null)
                         JMapViewerTree.this.createPopupMenu(layer).show(e.getComponent(), e.getX(), e.getY());
                 }
             }
         });
     }
+
     private JPopupMenu createPopupMenu(final AbstractLayer layer) {
         JMenuItem menuItemShow = new JMenuItem("show texts");
         JMenuItem menuItemHide = new JMenuItem("hide texts");
- 
+
         //Create the popup menu.
         JPopupMenu popup = new JPopupMenu();
-        
+
         // Create items
-        if(layer.isVisibleTexts()==null){
+        if (layer.isVisibleTexts() == null) {
             popup.add(menuItemShow);
             popup.add(menuItemHide);
-        }else if(layer.isVisibleTexts()) popup.add(menuItemHide);
+        } else if (layer.isVisibleTexts()) popup.add(menuItemHide);
         else popup.add(menuItemShow);
-        
+
         menuItemShow.addActionListener(new ActionListener(){
             @Override
             public void actionPerformed(ActionEvent arg0) {
                 setVisibleTexts(layer, true);
-                if(layer.getParent()!=null) layer.getParent().calculateVisibleTexts();
+                if (layer.getParent() != null) layer.getParent().calculateVisibleTexts();
                 map.repaint();
             }
         });
@@ -101,73 +106,90 @@ public class JMapViewerTree extends JPanel{
             @Override
             public void actionPerformed(ActionEvent arg0) {
                 setVisibleTexts(layer, false);
-                if(layer.getParent()!=null) layer.getParent().calculateVisibleTexts();
+                if (layer.getParent() != null) layer.getParent().calculateVisibleTexts();
                 map.repaint();
             }
         });
- 
+
         return popup;
     }
-    private void setVisibleTexts(AbstractLayer layer, boolean visible){
+
+    private static void setVisibleTexts(AbstractLayer layer, boolean visible) {
         layer.setVisibleTexts(visible);
-        if(layer instanceof LayerGroup){
-            LayerGroup group = (LayerGroup)layer;
-            if(group.getLayers()!=null) for(AbstractLayer al: group.getLayers()) setVisibleTexts(al, visible);
+        if (layer instanceof LayerGroup) {
+            LayerGroup group = (LayerGroup) layer;
+            if (group.getLayers() != null)
+                for (AbstractLayer al: group.getLayers()) {
+                    setVisibleTexts(al, visible);
+                }
         }
     }
-    public Layer addLayer(String name){
+
+    public Layer addLayer(String name) {
         Layer layer = new Layer(name);
         this.addLayer(layer);
         return layer;
     }
-    public JMapViewerTree addLayer(Layer layer){
+
+    public JMapViewerTree addLayer(Layer layer) {
         tree.addLayer(layer);
         return this;
     }
-    public JMapViewerTree addLayer(MapObject element){
+
+    public JMapViewerTree addLayer(MapObject element) {
         //element.getLayer().add(element);
         return addLayer(element.getLayer());
     }
-    public Layer removeFromLayer(MapObject element){
+
+    public Layer removeFromLayer(MapObject element) {
         element.getLayer().getElements().remove(element);
         return element.getLayer();
     }
-    public static int size(List<?> list){
-        return list==null?0:list.size();
+
+    public static int size(List<?> list) {
+        return list == null ? 0 : list.size();
     }
-    public JMapViewer getViewer(){
+
+    public JMapViewer getViewer() {
         return map;
     }
-    public CheckBoxTree getTree(){
+
+    public CheckBoxTree getTree() {
         return tree;
     }
+
     public void addMapObject(MapObject o){
-        
+
     }
-    public void setTreeVisible(boolean visible){
+
+    public void setTreeVisible(boolean visible) {
         removeAll();
         revalidate();
-        if(visible){
+        if (visible) {
             splitPane.setLeftComponent(treePanel);
             splitPane.setRightComponent(map);
             add(splitPane, BorderLayout.CENTER);
-        }else add(map, BorderLayout.CENTER);
+        } else add(map, BorderLayout.CENTER);
         repaint();
     }
-    private void createRefresh(){
+
+    private void createRefresh() {
         tree.getModel().addTreeModelListener(new TreeModelListener() {
             @Override
             public void treeNodesChanged(final TreeModelEvent e) {
                 repaint();
             }
+
             @Override
             public void treeNodesInserted(TreeModelEvent arg0) {
                 // TODO Auto-generated method stub
             }
+
             @Override
             public void treeNodesRemoved(TreeModelEvent arg0) {
                 // TODO Auto-generated method stub
             }
+
             @Override
             public void treeStructureChanged(TreeModelEvent arg0) {
                 // TODO Auto-generated method stub
diff --git a/src/org/openstreetmap/gui/jmapviewer/JobDispatcher.java b/src/org/openstreetmap/gui/jmapviewer/JobDispatcher.java
index ea22fbc..e689151 100644
--- a/src/org/openstreetmap/gui/jmapviewer/JobDispatcher.java
+++ b/src/org/openstreetmap/gui/jmapviewer/JobDispatcher.java
@@ -16,24 +16,11 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TileJob;
  *
  * @author Jan Peter Stotz
  */
-public class JobDispatcher {
+public final class JobDispatcher {
 
     private static final JobDispatcher instance = new JobDispatcher();
 
-    /**
-     * @return the singelton instance of the {@link JobDispatcher}
-     */
-    public static JobDispatcher getInstance() {
-        return instance;
-    }
-
-    private JobDispatcher() {
-        addWorkerThread().firstThread = true;
-    }
-
-    protected BlockingDeque<TileJob> jobQueue = new LinkedBlockingDeque<>();
-
-    protected static int workerThreadMaxCount = 8;
+    private static int workerThreadMaxCount = 8;
 
     /**
      * Specifies the time span in seconds that a worker thread waits for new
@@ -41,27 +28,40 @@ public class JobDispatcher {
      * terminates itself. Only the first worker thread works differently, it
      * ignores the timeout and will never terminate itself.
      */
-    protected static int workerThreadTimeout = 30;
+    private static int workerThreadTimeout = 30;
 
     /**
      * Type of queue, FIFO if <code>false</code>, LIFO if <code>true</code>
      */
-    protected boolean modeLIFO = false;
+    private boolean modeLIFO = false;
 
     /**
      * Total number of worker threads currently idle or active
      */
-    protected int workerThreadCount = 0;
+    private int workerThreadCount = 0;
 
     /**
      * Number of worker threads currently idle
      */
-    protected int workerThreadIdleCount = 0;
+    private int workerThreadIdleCount = 0;
 
     /**
      * Just an id for identifying an worker thread instance
      */
-    protected int workerThreadId = 0;
+    private int workerThreadId = 0;
+
+    private final BlockingDeque<TileJob> jobQueue = new LinkedBlockingDeque<>();
+
+    private JobDispatcher() {
+        addWorkerThread().firstThread = true;
+    }
+
+    /**
+     * @return the singelton instance of the {@link JobDispatcher}
+     */
+    public static JobDispatcher getInstance() {
+        return instance;
+    }
 
     /**
      * Removes all jobs from the queue that are currently not being processed.
@@ -72,8 +72,9 @@ public class JobDispatcher {
 
     /**
      * Function to set the maximum number of workers for tile loading.
+     * @param workers maximum number of workers
      */
-    static public void setMaxWorkers(int workers) {
+    public static void setMaxWorkers(int workers) {
         workerThreadMaxCount = workers;
     }
 
@@ -95,21 +96,24 @@ public class JobDispatcher {
      */
     public void addJob(TileJob job) {
         try {
-            if(job.getTile() != null) {
-                for(TileJob oldJob : jobQueue) {
-                    if(oldJob.getTile() == job.getTile()) {
+            if (job.getTile() != null) {
+                for (TileJob oldJob : jobQueue) {
+                    if (job.getTile().equals(oldJob.getTile())) {
                         return;
                     }
                 }
             }
             jobQueue.put(job);
-            if (workerThreadIdleCount == 0 && workerThreadCount < workerThreadMaxCount)
-                addWorkerThread();
+            synchronized (this) {
+                if (workerThreadIdleCount == 0 && workerThreadCount < workerThreadMaxCount)
+                    addWorkerThread();
+            }
         } catch (InterruptedException e) {
+            System.err.println("InterruptedException: " + e.getMessage());
         }
     }
 
-    protected JobThread addWorkerThread() {
+    private JobThread addWorkerThread() {
         JobThread jobThread = new JobThread(++workerThreadId);
         synchronized (this) {
             workerThreadCount++;
@@ -120,9 +124,13 @@ public class JobDispatcher {
 
     public class JobThread extends Thread {
 
-        Runnable job;
-        boolean firstThread = false;
+        private Runnable job;
+        private boolean firstThread = false;
 
+        /**
+         * Constructs a new {@code JobThread}.
+         * @param threadId Thread ID
+         */
         public JobThread(int threadId) {
             super("OSMJobThread " + threadId);
             setDaemon(true);
@@ -143,7 +151,7 @@ public class JobDispatcher {
                     synchronized (instance) {
                         workerThreadIdleCount++;
                     }
-                    if(modeLIFO) {
+                    if (modeLIFO) {
                         if (firstThread)
                             job = jobQueue.takeLast();
                         else
@@ -172,5 +180,4 @@ public class JobDispatcher {
             }
         }
     }
-
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/Layer.java b/src/org/openstreetmap/gui/jmapviewer/Layer.java
index 5d73c39..ede87cb 100644
--- a/src/org/openstreetmap/gui/jmapviewer/Layer.java
+++ b/src/org/openstreetmap/gui/jmapviewer/Layer.java
@@ -8,33 +8,42 @@ import org.openstreetmap.gui.jmapviewer.interfaces.MapObject;
 public class Layer extends AbstractLayer{
     private List<MapObject> elements;
     
-    public Layer(String name){
+    public Layer(String name) {
         super(name);
     }
-    public Layer(String name, String description){
+
+    public Layer(String name, String description) {
         super(name, description);
     }
-    public Layer(String name, Style style){
+
+    public Layer(String name, Style style) {
         super(name, style);
     }
-    public Layer(String name, String description, Style style){
+
+    public Layer(String name, String description, Style style) {
         super(name, description, style);
     }
-    public Layer(LayerGroup parent, String name){
+
+    public Layer(LayerGroup parent, String name) {
         super(parent, name);
     }
-    public Layer(LayerGroup parent, String name, Style style){
+
+    public Layer(LayerGroup parent, String name, Style style) {
         super(parent, name, style);
     }
-    public Layer(LayerGroup parent, String name, String description, Style style){
+
+    public Layer(LayerGroup parent, String name, String description, Style style) {
         super(parent, name, description, style);
     }
+
     public List<MapObject> getElements() {
         return elements;
     }
+
     public void setElements(List<MapObject> elements) {
         this.elements = elements;
     }
+
     public Layer add(MapObject element) {
         element.setLayer(this);
         elements = add(elements, element);
diff --git a/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java b/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java
index a27a348..2fea5a3 100644
--- a/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java
+++ b/src/org/openstreetmap/gui/jmapviewer/LayerGroup.java
@@ -5,55 +5,67 @@ import java.util.List;
 
 public class LayerGroup extends AbstractLayer{
     private List<AbstractLayer> layers;
-    
-    public LayerGroup(String name){
+
+    public LayerGroup(String name) {
         super(name);
     }
-    public LayerGroup(String name, String description){
+
+    public LayerGroup(String name, String description) {
         super(name, description);
     }
-    public LayerGroup(String name, Style style){
+
+    public LayerGroup(String name, Style style) {
         super(name, style);
     }
-    public LayerGroup(String name, String description, Style style){
+
+    public LayerGroup(String name, String description, Style style) {
         super(name, description, style);
     }
-    public LayerGroup(LayerGroup parent, String name){
+
+    public LayerGroup(LayerGroup parent, String name) {
         super(parent, name);
     }
-    public LayerGroup(LayerGroup parent, String name, String description, Style style){
+
+    public LayerGroup(LayerGroup parent, String name, String description, Style style) {
         super(name, description, style);
     }
+
     public List<AbstractLayer> getLayers() {
         return layers;
     }
+
     public void setElements(List<AbstractLayer> layers) {
         this.layers = layers;
     }
+
     public Layer addLayer(String name) {
         Layer layer = new Layer(this, name);
         layers = add(layers, layer);
         return layer;
     }
+
     public LayerGroup add(AbstractLayer layer) {
         layer.setParent(this);
         layers = add(layers, layer);
         return this;
     }
-    public void calculateVisibleTexts(){
-        Boolean calculate=null;
-        if(layers!=null&&layers.size()>0){
-            calculate=layers.get(0).isVisibleTexts();
-            for(int i=1;i<layers.size(); i++){
+
+    public void calculateVisibleTexts() {
+        Boolean calculate = null;
+        if (layers != null && !layers.isEmpty()) {
+            calculate = layers.get(0).isVisibleTexts();
+            for (int i = 1; i < layers.size(); i++) {
                 calculate = resultOf(calculate, layers.get(i).isVisibleTexts());
             }
         }
         setVisibleTexts(calculate);
-        if(getParent()!=null) getParent().calculateVisibleTexts();
+        if (getParent() != null) getParent().calculateVisibleTexts();
     }
-    public Boolean resultOf(Boolean b1, Boolean b2){
-        if(b1==null||b2==null) return null;
-        else if(b1.booleanValue() == b2.booleanValue()) return b1.booleanValue();
-        else return null;
+
+    public Boolean resultOf(Boolean b1, Boolean b2) {
+        if (b1 != null && b1.equals(b2)) {
+            return b1;
+        }
+        return Boolean.FALSE;
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java b/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java
index bfdf7be..d3a0dbf 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MapMarkerCircle.java
@@ -20,28 +20,80 @@ import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
  */
 public class MapMarkerCircle extends MapObjectImpl implements MapMarker {
 
-    Coordinate coord;
-    double radius;
-    STYLE markerStyle;
+    private Coordinate coord;
+    private double radius;
+    private STYLE markerStyle;
 
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param coord Coordinates of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(Coordinate coord, double radius) {
         this(null, null, coord, radius);
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param name Name of the map marker
+     * @param coord Coordinates of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(String name, Coordinate coord, double radius) {
         this(null, name, coord, radius);
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param layer Layer of the map marker
+     * @param coord Coordinates of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(Layer layer, Coordinate coord, double radius) {
         this(layer, null, coord, radius);
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param lat Latitude of the map marker
+     * @param lon Longitude of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(double lat, double lon, double radius) {
-        this(null, null, new Coordinate(lat,lon), radius);
+        this(null, null, new Coordinate(lat, lon), radius);
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param layer Layer of the map marker
+     * @param lat Latitude of the map marker
+     * @param lon Longitude of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(Layer layer, double lat, double lon, double radius) {
-        this(layer, null, new Coordinate(lat,lon), radius);
+        this(layer, null, new Coordinate(lat, lon), radius);
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param layer Layer of the map marker
+     * @param name Name of the map marker
+     * @param coord Coordinates of the map marker
+     * @param radius Radius of the map marker position
+     */
     public MapMarkerCircle(Layer layer, String name, Coordinate coord, double radius) {
         this(layer, name, coord, radius, STYLE.VARIABLE, getDefaultStyle());
     }
+
+    /**
+     * Constructs a new {@code MapMarkerCircle}.
+     * @param layer Layer of the map marker
+     * @param name Name of the map marker
+     * @param coord Coordinates of the map marker
+     * @param radius Radius of the map marker position
+     * @param markerStyle Marker style (fixed or variable)
+     * @param style Graphical style
+     */
     public MapMarkerCircle(Layer layer, String name, Coordinate coord, double radius, STYLE markerStyle, Style style) {
         super(layer, name, style);
         this.markerStyle = markerStyle;
@@ -49,30 +101,37 @@ public class MapMarkerCircle extends MapObjectImpl implements MapMarker {
         this.radius = radius;
     }
 
-    public Coordinate getCoordinate(){
+    @Override
+    public Coordinate getCoordinate() {
         return coord;
     }
+
+    @Override
     public double getLat() {
         return coord.getLat();
     }
 
+    @Override
     public double getLon() {
         return coord.getLon();
     }
 
+    @Override
     public double getRadius() {
         return radius;
     }
 
+    @Override
     public STYLE getMarkerStyle() {
         return markerStyle;
     }
 
-    public void paint(Graphics g, Point position, int radio) {
-        int size_h = radio;
+    @Override
+    public void paint(Graphics g, Point position, int radius) {
+        int size_h = radius;
         int size = size_h * 2;
 
-        if (g instanceof Graphics2D && getBackColor()!=null) {
+        if (g instanceof Graphics2D && getBackColor() != null) {
             Graphics2D g2 = (Graphics2D) g;
             Composite oldComposite = g2.getComposite();
             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
@@ -83,24 +142,27 @@ public class MapMarkerCircle extends MapObjectImpl implements MapMarker {
         g.setColor(getColor());
         g.drawOval(position.x - size_h, position.y - size_h, size, size);
 
-        if(getLayer()==null||getLayer().isVisibleTexts()) paintText(g, position);
+        if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, position);
     }
 
-    public static Style getDefaultStyle(){
-        return new Style(Color.ORANGE, new Color(200,200,200,200), null, getDefaultFont());
+    public static Style getDefaultStyle() {
+        return new Style(Color.ORANGE, new Color(200, 200, 200, 200), null, getDefaultFont());
     }
+
     @Override
     public String toString() {
         return "MapMarker at " + getLat() + " " + getLon();
     }
+
     @Override
     public void setLat(double lat) {
-        if(coord==null) coord = new Coordinate(lat,0);
+        if (coord == null) coord = new Coordinate(lat, 0);
         else coord.setLat(lat);
     }
+
     @Override
     public void setLon(double lon) {
-        if(coord==null) coord = new Coordinate(0,lon);
+        if (coord == null) coord = new Coordinate(0, lon);
         else coord.setLon(lon);
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java b/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java
index 1da1204..f11e256 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MapMarkerDot.java
@@ -20,33 +20,41 @@ public class MapMarkerDot extends MapMarkerCircle {
     public MapMarkerDot(Coordinate coord) {
         this(null, null, coord);
     }
+
     public MapMarkerDot(String name, Coordinate coord) {
         this(null, name, coord);
     }
+
     public MapMarkerDot(Layer layer, Coordinate coord) {
         this(layer, null, coord);
     }
+
     public MapMarkerDot(Layer layer, String name, Coordinate coord) {
         this(layer, name, coord, getDefaultStyle());
     }
+
     public MapMarkerDot(Color color, double lat, double lon) {
         this(null, null, lat, lon);
         setColor(color);
     }
+
     public MapMarkerDot(double lat, double lon) {
         this(null, null, lat, lon);
     }
+
     public MapMarkerDot(Layer layer, double lat, double lon) {
         this(layer, null, lat, lon);
     }
+
     public MapMarkerDot(Layer layer, String name, double lat, double lon) {
         this(layer, name, new Coordinate(lat, lon), getDefaultStyle());
     }
+
     public MapMarkerDot(Layer layer, String name, Coordinate coord, Style style) {
         super(layer, name, coord, DOT_RADIUS, STYLE.FIXED, style);
     }
 
-    public static Style getDefaultStyle(){
+    public static Style getDefaultStyle() {
         return new Style(Color.BLACK, Color.YELLOW, null, getDefaultFont());
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java
index 2e9cd90..8cddfb3 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MapObjectImpl.java
@@ -18,87 +18,109 @@ public abstract class MapObjectImpl {
     public MapObjectImpl(String name) {
         this(null, name, null);
     }
+
     public MapObjectImpl(Layer layer) {
         this(layer, null, null);
     }
+
     public MapObjectImpl(Layer layer, String name, Style style) {
         super();
         this.layer = layer;
         this.name = name;
         this.style = style;
     }
+
     public Layer getLayer() {
         return layer;
     }
+
     public void setLayer(Layer layer) {
         this.layer = layer;
     }
-    public Style getStyle(){
+
+    public Style getStyle() {
         return style;
     }
-    public Style getStyleAssigned(){
+
+    public Style getStyleAssigned() {
         return style == null ? (layer == null ? null : layer.getStyle()) : style;
     }
-    public void setStyle(Style style){
+
+    public void setStyle(Style style) {
         this.style = style;
     }
+
     public Color getColor() {
         Style styleAssigned = getStyleAssigned();
         return styleAssigned == null ? null : getStyleAssigned().getColor();
     }
+
     public void setColor(Color color) {
-        if(style==null&&color!=null) style=new Style();
-        if(style!=null) style.setColor(color);
+        if (style == null && color != null) style = new Style();
+        if (style != null) style.setColor(color);
     }
 
     public Color getBackColor() {
         Style styleAssigned = getStyleAssigned();
         return styleAssigned == null ? null : getStyleAssigned().getBackColor();
     }
+
     public void setBackColor(Color backColor) {
-        if(style==null&&backColor!=null) style=new Style();
-        if(style!=null) style.setBackColor(backColor);
+        if (style == null && backColor != null) style = new Style();
+        if (style != null) style.setBackColor(backColor);
     }
 
     public Stroke getStroke() {
         Style styleAssigned = getStyleAssigned();
         return styleAssigned == null ? null : getStyleAssigned().getStroke();
     }
+
     public void setStroke(Stroke stroke) {
-        if(style==null&&stroke!=null) style=new Style();
-        if(style!=null) style.setStroke(stroke);
+        if (style == null && stroke != null) style = new Style();
+        if (style != null) style.setStroke(stroke);
     }
-    
+
     public Font getFont() {
         Style styleAssigned = getStyleAssigned();
         return styleAssigned == null ? null : getStyleAssigned().getFont();
     }
+
     public void setFont(Font font) {
-        if(style==null&&font!=null) style=new Style();
-        if(style!=null) style.setFont(font);
+        if (style == null && font != null) style = new Style();
+        if (style != null) style.setFont(font);
     }
-    private boolean isVisibleLayer(){
-        return layer==null||layer.isVisible()==null?true:layer.isVisible();
+
+    private boolean isVisibleLayer() {
+        return layer == null || layer.isVisible() == null ? true : layer.isVisible();
     }
+
     public boolean isVisible() {
-        return visible==null?isVisibleLayer():visible.booleanValue();
+        return visible == null ? isVisibleLayer() : visible.booleanValue();
     }
+
     public void setVisible(Boolean visible) {
         this.visible = visible;
     }
+
     public String getName() {
         return name;
     }
+
     public void setName(String txt) {
         this.name = txt;
     }
-    public static Font getDefaultFont(){
+
+    public static Font getDefaultFont() {
         Font f = UIManager.getDefaults().getFont("TextField.font");
+        if (f == null) {
+            f = Font.decode(null);
+        }
         return new Font(f.getName(), Font.BOLD, f.getSize());
     }
+
     public void paintText(Graphics g, Point position) {
-        if(name!=null && g!=null && position!=null){
-            if(getFont()==null){
+        if (name != null && g != null && position != null) {
+            if (getFont() == null) {
                 Font f = getDefaultFont();
                 setFont(new Font(f.getName(), Font.BOLD, f.getSize()));
             }
diff --git a/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java
index 521935b..d993c2c 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MapPolygonImpl.java
@@ -24,24 +24,31 @@ public class MapPolygonImpl extends MapObjectImpl implements MapPolygon {
     public MapPolygonImpl(ICoordinate ... points) {
         this(null, null, points);
     }
+
     public MapPolygonImpl(List<? extends ICoordinate> points) {
         this(null, null, points);
     }
+
     public MapPolygonImpl(String name, List<? extends ICoordinate> points) {
         this(null, name, points);
     }
+
     public MapPolygonImpl(String name, ICoordinate ... points) {
         this(null, name, points);
     }
+
     public MapPolygonImpl(Layer layer, List<? extends ICoordinate> points) {
         this(layer, null, points);
     }
+
     public MapPolygonImpl(Layer layer, String name, List<? extends ICoordinate> points) {
         this(layer, name, points, getDefaultStyle());
     }
+
     public MapPolygonImpl(Layer layer, String name, ICoordinate ... points) {
         this(layer, name, Arrays.asList(points), getDefaultStyle());
     }
+
     public MapPolygonImpl(Layer layer, String name, List<? extends ICoordinate> points, Style style) {
         super(layer, name, style);
         this.points = points;
@@ -75,7 +82,7 @@ public class MapPolygonImpl extends MapObjectImpl implements MapPolygon {
         }
         // Draw
         g.drawPolygon(polygon);
-        if (g instanceof Graphics2D && getBackColor()!=null) {
+        if (g instanceof Graphics2D && getBackColor() != null) {
             Graphics2D g2 = (Graphics2D) g;
             Composite oldComposite = g2.getComposite();
             g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
@@ -90,12 +97,12 @@ public class MapPolygonImpl extends MapObjectImpl implements MapPolygon {
         }
         Rectangle rec = polygon.getBounds();
         Point corner = rec.getLocation();
-        Point p= new Point(corner.x+(rec.width/2), corner.y+(rec.height/2));
-        if(getLayer()==null||getLayer().isVisibleTexts()) paintText(g, p);
+        Point p = new Point(corner.x+(rec.width/2), corner.y+(rec.height/2));
+        if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, p);
     }
 
-    public static Style getDefaultStyle(){
-        return new Style(Color.BLUE, new Color(100,100,100,50), new BasicStroke(2), getDefaultFont());
+    public static Style getDefaultStyle() {
+        return new Style(Color.BLUE, new Color(100, 100, 100, 50), new BasicStroke(2), getDefaultFont());
     }
 
     @Override
diff --git a/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java b/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java
index 4d09ede..4d6efde 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MapRectangleImpl.java
@@ -18,15 +18,19 @@ public class MapRectangleImpl extends MapObjectImpl implements MapRectangle {
     public MapRectangleImpl(Coordinate topLeft, Coordinate bottomRight) {
         this(null, null, topLeft, bottomRight);
     }
+
     public MapRectangleImpl(String name, Coordinate topLeft, Coordinate bottomRight) {
         this(null, name, topLeft, bottomRight);
     }
+
     public MapRectangleImpl(Layer layer, Coordinate topLeft, Coordinate bottomRight) {
         this(layer, null, topLeft, bottomRight);
     }
+
     public MapRectangleImpl(Layer layer, String name, Coordinate topLeft, Coordinate bottomRight) {
         this(layer, name, topLeft, bottomRight, getDefaultStyle());
     }
+
     public MapRectangleImpl(Layer layer, String name, Coordinate topLeft, Coordinate bottomRight, Style style) {
         super(layer, name, style);
         this.topLeft = topLeft;
@@ -61,13 +65,13 @@ public class MapRectangleImpl extends MapObjectImpl implements MapRectangle {
         if (g instanceof Graphics2D) {
             ((Graphics2D) g).setStroke(oldStroke);
         }
-        int width=bottomRight.x-topLeft.x;
-        int height=bottomRight.y-topLeft.y;
-        Point p= new Point(topLeft.x+(width/2), topLeft.y+(height/2));
-        if(getLayer()==null||getLayer().isVisibleTexts()) paintText(g, p);
+        int width = bottomRight.x-topLeft.x;
+        int height = bottomRight.y-topLeft.y;
+        Point p = new Point(topLeft.x+(width/2), topLeft.y+(height/2));
+        if (getLayer() == null || getLayer().isVisibleTexts()) paintText(g, p);
     }
 
-    public static Style getDefaultStyle(){
+    public static Style getDefaultStyle() {
         return new Style(Color.BLUE, null, new BasicStroke(2), getDefaultFont());
     }
 
diff --git a/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java b/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
index 9192029..84ca330 100644
--- a/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
+++ b/src/org/openstreetmap/gui/jmapviewer/MemoryTileCache.java
@@ -22,7 +22,7 @@ public class MemoryTileCache implements TileCache {
     /**
      * Default cache size
      */
-    protected int cacheSize = 200;
+    protected int cacheSize;
 
     protected final Map<String, CacheEntry> hash;
 
@@ -35,6 +35,15 @@ public class MemoryTileCache implements TileCache {
      * Constructs a new {@code MemoryTileCache}.
      */
     public MemoryTileCache() {
+        this(200);
+    }
+
+    /**
+     * Constructs a new {@code MemoryTileCache}.
+     * @param cacheSize size of the cache
+     */
+    public MemoryTileCache(int cacheSize) {
+        this.cacheSize = cacheSize;
         hash = new HashMap<>(cacheSize);
         lruTiles = new CacheLinkedListElement();
     }
@@ -42,11 +51,11 @@ public class MemoryTileCache implements TileCache {
     @Override
     public synchronized void addTile(Tile tile) {
         CacheEntry entry = createCacheEntry(tile);
-            hash.put(tile.getKey(), entry);
-            lruTiles.addFirst(entry);
-            if (hash.size() > cacheSize) {
-                removeOldEntries();
-            }
+        hash.put(tile.getKey(), entry);
+        lruTiles.addFirst(entry);
+        if (hash.size() > cacheSize) {
+            removeOldEntries();
+        }
     }
 
     @Override
@@ -90,11 +99,11 @@ public class MemoryTileCache implements TileCache {
     }
 
     @Override
-    public int getTileCount() {
+    public synchronized int getTileCount() {
         return hash.size();
     }
 
-    public int getCacheSize() {
+    public synchronized int getCacheSize() {
         return cacheSize;
     }
 
@@ -115,27 +124,13 @@ public class MemoryTileCache implements TileCache {
      * {@link #next} and {@link #prev} item in the list.
      */
     protected static class CacheEntry {
-        Tile tile;
-
-        CacheEntry next;
-        CacheEntry prev;
+        private Tile tile;
+        private CacheEntry next;
+        private CacheEntry prev;
 
         protected CacheEntry(Tile tile) {
             this.tile = tile;
         }
-
-        public Tile getTile() {
-            return tile;
-        }
-
-        public CacheEntry getNext() {
-            return next;
-        }
-
-        public CacheEntry getPrev() {
-            return prev;
-        }
-
     }
 
     /**
@@ -150,6 +145,9 @@ public class MemoryTileCache implements TileCache {
         protected CacheEntry lastElement;
         protected int elementCount;
 
+        /**
+         * Constructs a new {@code CacheLinkedListElement}.
+         */
         public CacheLinkedListElement() {
             clear();
         }
@@ -221,6 +219,5 @@ public class MemoryTileCache implements TileCache {
         public CacheEntry getFirstElement() {
             return firstElement;
         }
-
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java b/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
index 0556783..f475e8a 100644
--- a/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
+++ b/src/org/openstreetmap/gui/jmapviewer/OsmMercator.java
@@ -7,13 +7,15 @@ package org.openstreetmap.gui.jmapviewer;
  * into latitude and longitude (on the WGS84 ellipsoid) and vice versa. Map
  * space is measured in pixels. The origin of the map space is the top left
  * corner. The map space origin (0,0) has latitude ~85 and longitude -180.
+ * @author Jan Peter Stotz
+ * @author Jason Huntley
  */
 public class OsmMercator {
 
     /**
      * default tile size
      */
-    public static int DEFAUL_TILE_SIZE = 256;
+    public static final int DEFAUL_TILE_SIZE = 256;
     /** maximum latitude (north) for mercator display */
     public static final double MAX_LAT = 85.05112877980659;
     /** minimum latitude (south) for mercator display */
@@ -37,7 +39,7 @@ public class OsmMercator {
 
     /**
      * Creates instance with provided tile size.
-     * @param tileSize
+     * @param tileSize tile size in pixels
      */
     public OsmMercator(int tileSize) {
         this.tileSize = tileSize;
@@ -63,7 +65,7 @@ public class OsmMercator {
     }
 
     public int falseNorthing(int aZoomlevel) {
-        return (-1 * getMaxPixels(aZoomlevel) / 2);
+        return -1 * getMaxPixels(aZoomlevel) / 2;
     }
 
     /**
@@ -76,13 +78,12 @@ public class OsmMercator {
      *
      * @param zoomLevel the zoom level
      * @return the distance
-     * @author Jason Huntley
      */
     public double getDistance(int x1, int y1, int x2, int y2, int zoomLevel) {
-        double la1 = YToLat(y1, zoomLevel);
-        double lo1 = XToLon(x1, zoomLevel);
-        double la2 = YToLat(y2, zoomLevel);
-        double lo2 = XToLon(x2, zoomLevel);
+        double la1 = yToLat(y1, zoomLevel);
+        double lo1 = xToLon(x1, zoomLevel);
+        double la2 = yToLat(y2, zoomLevel);
+        double lo2 = xToLon(x2, zoomLevel);
 
         return getDistance(la1, lo1, la2, lo2);
     }
@@ -95,19 +96,18 @@ public class OsmMercator {
      * @param la2 the Latitude from 2nd coordinate in degrees
      * @param lo2 the Longitude from 2nd coordinate in degrees
      * @return the distance
-     * @author Jason Huntley
      */
     public double getDistance(double la1, double lo1, double la2, double lo2) {
         double aStartLat = Math.toRadians(la1);
         double aStartLong = Math.toRadians(lo1);
-        double aEndLat =Math.toRadians(la2);
+        double aEndLat = Math.toRadians(la2);
         double aEndLong = Math.toRadians(lo2);
 
         double distance = Math.acos(Math.sin(aStartLat) * Math.sin(aEndLat)
                 + Math.cos(aStartLat) * Math.cos(aEndLat)
                 * Math.cos(aEndLong - aStartLong));
 
-        return (EARTH_RADIUS * distance);
+        return EARTH_RADIUS * distance;
     }
 
     /**
@@ -125,12 +125,12 @@ public class OsmMercator {
      *
      * @param aLongitude
      *            [-180..180]
+     * @param aZoomlevel zoom level
      * @return [0..2^Zoomlevel*TILE_SIZE[
-     * @author Jan Peter Stotz
      */
-    public double LonToX(double aLongitude, int aZoomlevel) {
+    public double lonToX(double aLongitude, int aZoomlevel) {
         int mp = getMaxPixels(aZoomlevel);
-        double x = (mp * (aLongitude + 180l)) / 360l;
+        double x = (mp * (aLongitude + 180L)) / 360L;
         return Math.min(x, mp);
     }
 
@@ -149,10 +149,10 @@ public class OsmMercator {
      * </p>
      * @param aLat
      *            [-90...90]
+     * @param aZoomlevel zoom level
      * @return [0..2^Zoomlevel*TILE_SIZE[
-     * @author Jan Peter Stotz
      */
-    public double LatToY(double aLat, int aZoomlevel) {
+    public double latToY(double aLat, int aZoomlevel) {
         if (aLat < MIN_LAT)
             aLat = MIN_LAT;
         else if (aLat > MAX_LAT)
@@ -179,10 +179,10 @@ public class OsmMercator {
      * </p>
      * @param aX
      *            [0..2^Zoomlevel*TILE_WIDTH[
+     * @param aZoomlevel zoom level
      * @return ]-180..180[
-     * @author Jan Peter Stotz
      */
-    public double XToLon(int aX, int aZoomlevel) {
+    public double xToLon(int aX, int aZoomlevel) {
         return ((360d * aX) / getMaxPixels(aZoomlevel)) - 180.0;
     }
 
@@ -191,9 +191,10 @@ public class OsmMercator {
      *
      * @param aY
      *            [0..2^Zoomlevel*TILE_WIDTH[
+     * @param aZoomlevel zoom level
      * @return [MIN_LAT..MAX_LAT] is about [-85..85]
      */
-    public double YToLat(int aY, int aZoomlevel) {
+    public double yToLat(int aY, int aZoomlevel) {
         aY += falseNorthing(aZoomlevel);
         double latitude = (Math.PI / 2) - (2 * Math.atan(Math.exp(-1.0 * aY / radius(aZoomlevel))));
         return -1 * Math.toDegrees(latitude);
diff --git a/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java b/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
index d138714..c26a61c 100644
--- a/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
+++ b/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
@@ -21,6 +21,77 @@ import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
  */
 public class OsmTileLoader implements TileLoader {
 
+    private final class OsmTileJob implements TileJob {
+        private final Tile tile;
+        private InputStream input = null;
+        private boolean force = false;
+
+        private OsmTileJob(Tile tile) {
+            this.tile = tile;
+        }
+
+        @Override
+        public void run() {
+            synchronized (tile) {
+                if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
+                    return;
+                tile.loaded = false;
+                tile.error = false;
+                tile.loading = true;
+            }
+            try {
+                URLConnection conn = loadTileFromOsm(tile);
+                if (force) {
+                    conn.setUseCaches(false);
+                }
+                loadTileMetadata(tile, conn);
+                if ("no-tile".equals(tile.getValue("tile-info"))) {
+                    tile.setError("No tile at this zoom level");
+                } else {
+                    input = conn.getInputStream();
+                    try {
+                        tile.loadImage(input);
+                    } finally {
+                        input.close();
+                        input = null;
+                    }
+                }
+                tile.setLoaded(true);
+                listener.tileLoadingFinished(tile, true);
+            } catch (Exception e) {
+                tile.setError(e.getMessage());
+                listener.tileLoadingFinished(tile, false);
+                if (input == null) {
+                    try {
+                        System.err.println("Failed loading " + tile.getUrl() +": "
+                                +e.getClass() + ": " + e.getMessage());
+                    } catch (IOException ioe) {
+                        ioe.printStackTrace();
+                    }
+                }
+            } finally {
+                tile.loading = false;
+                tile.setLoaded(true);
+            }
+        }
+
+        @Override
+        public Tile getTile() {
+            return tile;
+        }
+
+        @Override
+        public void submit() {
+            submit(false);
+        }
+
+        @Override
+        public void submit(boolean force) {
+            this.force = force;
+            run();
+        }
+    }
+
     /**
      * Holds the HTTP headers. Insert e.g. User-Agent here when default should not be used.
      */
@@ -32,77 +103,20 @@ public class OsmTileLoader implements TileLoader {
     protected TileLoaderListener listener;
 
     public OsmTileLoader(TileLoaderListener listener) {
-        headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
+        this(listener, null);
+    }
+
+    public OsmTileLoader(TileLoaderListener listener, Map<String, String> headers) {
+        this.headers.put("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
+        if (headers != null) {
+            this.headers.putAll(headers);
+        }
         this.listener = listener;
     }
 
+    @Override
     public TileJob createTileLoaderJob(final Tile tile) {
-        return new TileJob() {
-
-            InputStream input = null;
-            boolean force = false;
-
-            public void run() {
-                synchronized (tile) {
-                    if ((tile.isLoaded() && !tile.hasError()) || tile.isLoading())
-                        return;
-                    tile.loaded = false;
-                    tile.error = false;
-                    tile.loading = true;
-                }
-                try {
-                    URLConnection conn = loadTileFromOsm(tile);
-                    if (force) {
-                        conn.setUseCaches(false);
-                    }
-                    loadTileMetadata(tile, conn);
-                    if ("no-tile".equals(tile.getValue("tile-info"))) {
-                        tile.setError("No tile at this zoom level");
-                    } else {
-                        input = conn.getInputStream();
-                        try {
-                            tile.loadImage(input);
-                        } finally {
-                            input.close();
-                            input = null;
-                        }
-                    }
-                    tile.setLoaded(true);
-                    listener.tileLoadingFinished(tile, true);
-                } catch (Exception e) {
-                    tile.setError(e.getMessage());
-                    listener.tileLoadingFinished(tile, false);
-                    if (input == null) {
-                        try {
-                            System.err.println("Failed loading " + tile.getUrl() +": "
-                                    +e.getClass() + ": " + e.getMessage());
-                        } catch (IOException ioe) {
-                            ioe.printStackTrace();
-                        }
-                    }
-                } finally {
-                    tile.loading = false;
-                    tile.setLoaded(true);
-                }
-            }
-
-            public Tile getTile() {
-                return tile;
-            }
-
-            @Override
-            public void submit() {
-                submit(false);
-
-            }
-
-            @Override
-            public void submit(boolean force) {
-                this.force = force;
-                run();
-            }
-
-        };
+        return new OsmTileJob(tile);
     }
 
     protected URLConnection loadTileFromOsm(Tile tile) throws IOException {
@@ -110,7 +124,7 @@ public class OsmTileLoader implements TileLoader {
         url = new URL(tile.getUrl());
         URLConnection urlConn = url.openConnection();
         if (urlConn instanceof HttpURLConnection) {
-            prepareHttpUrlConnection((HttpURLConnection)urlConn);
+            prepareHttpUrlConnection((HttpURLConnection) urlConn);
         }
         return urlConn;
     }
@@ -137,7 +151,12 @@ public class OsmTileLoader implements TileLoader {
                         }
                     }
                 }
-            } catch (NumberFormatException e) {} //ignore malformed Cache-Control headers
+            } catch (NumberFormatException e) {
+                // ignore malformed Cache-Control headers
+                if (JMapViewer.debug) {
+                    System.err.println(e.getMessage());
+                }
+            }
         }
         if (!lng.equals(0L)) {
             tile.putValue("expires", lng.toString());
@@ -145,12 +164,12 @@ public class OsmTileLoader implements TileLoader {
     }
 
     protected void prepareHttpUrlConnection(HttpURLConnection urlConn) {
-        for(Entry<String, String> e : headers.entrySet()) {
+        for (Entry<String, String> e : headers.entrySet()) {
             urlConn.setRequestProperty(e.getKey(), e.getValue());
         }
-        if(timeoutConnect != 0)
+        if (timeoutConnect != 0)
             urlConn.setConnectTimeout(timeoutConnect);
-        if(timeoutRead != 0)
+        if (timeoutRead != 0)
             urlConn.setReadTimeout(timeoutRead);
     }
 
@@ -158,5 +177,4 @@ public class OsmTileLoader implements TileLoader {
     public String toString() {
         return getClass().getSimpleName();
     }
-
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/Style.java b/src/org/openstreetmap/gui/jmapviewer/Style.java
index 44bad2b..1302d83 100644
--- a/src/org/openstreetmap/gui/jmapviewer/Style.java
+++ b/src/org/openstreetmap/gui/jmapviewer/Style.java
@@ -15,9 +15,10 @@ public class Style {
     private static final AlphaComposite TRANSPARENCY = AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
     private static final AlphaComposite OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC);
 
-    public Style(){
+    public Style() {
         super();
     }
+
     public Style(Color color, Color backColor, Stroke stroke, Font font) {
         super();
         this.color = color;
@@ -29,34 +30,44 @@ public class Style {
     public Color getColor() {
         return color;
     }
+
     public void setColor(Color color) {
         this.color = color;
     }
+
     public Color getBackColor() {
         return backColor;
     }
+
     public void setBackColor(Color backColor) {
         this.backColor = backColor;
     }
+
     public Stroke getStroke() {
         return stroke;
     }
+
     public void setStroke(Stroke stroke) {
         this.stroke = stroke;
     }
+
     public Font getFont() {
         return font;
     }
+
     public void setFont(Font font) {
         this.font = font;
     }
-    private AlphaComposite getAlphaComposite(Color color){
-        return color.getAlpha()==255?OPAQUE:TRANSPARENCY;
+
+    private static AlphaComposite getAlphaComposite(Color color) {
+        return color.getAlpha() == 255 ? OPAQUE : TRANSPARENCY;
     }
-    public AlphaComposite getAlphaComposite(){
+
+    public AlphaComposite getAlphaComposite() {
         return getAlphaComposite(color);
     }
-    public AlphaComposite getBackAlphaComposite(){
+
+    public AlphaComposite getBackAlphaComposite() {
         return getAlphaComposite(backColor);
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/Tile.java b/src/org/openstreetmap/gui/jmapviewer/Tile.java
index 8cd511d..d4bf072 100644
--- a/src/org/openstreetmap/gui/jmapviewer/Tile.java
+++ b/src/org/openstreetmap/gui/jmapviewer/Tile.java
@@ -9,6 +9,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.Callable;
 
 import javax.imageio.ImageIO;
 
@@ -26,21 +27,12 @@ public class Tile {
     /**
      * Hourglass image that is displayed until a map tile has been loaded, except for overlay sources
      */
-    public static BufferedImage LOADING_IMAGE;
+    public static final BufferedImage LOADING_IMAGE = loadImage("images/hourglass.png");
 
     /**
      * Red cross image that is displayed after a loading error, except for overlay sources
      */
-    public static BufferedImage ERROR_IMAGE;
-
-    static {
-        try {
-            LOADING_IMAGE = ImageIO.read(JMapViewer.class.getResourceAsStream("images/hourglass.png"));
-            ERROR_IMAGE = ImageIO.read(JMapViewer.class.getResourceAsStream("images/error.png"));
-        } catch (Exception ex) {
-            ex.printStackTrace();
-        }
-    }
+    public static final BufferedImage ERROR_IMAGE = loadImage("images/error.png");
 
     protected TileSource source;
     protected int xtile;
@@ -86,56 +78,121 @@ public class Tile {
         this.key = getTileKey(source, xtile, ytile, zoom);
     }
 
+    private static BufferedImage loadImage(String path) {
+        try {
+            return ImageIO.read(JMapViewer.class.getResourceAsStream(path));
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+
+    private static class CachedCallable<V> implements Callable<V> {
+        private V result = null;
+        private Callable<V> callable;
+
+        /**
+         * Wraps callable so it is evaluated only once
+         * @param callable to cache
+         */
+        public CachedCallable(Callable<V> callable) {
+            this.callable = callable;
+        }
+
+        @Override
+        public synchronized V call() {
+            try {
+                if (result == null) {
+                    result = callable.call();
+                }
+                return result;
+            } catch (Exception e) {
+                // this should not happen here
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
     /**
      * Tries to get tiles of a lower or higher zoom level (one or two level
-     * difference) from cache and use it as a placeholder until the tile has
-     * been loaded.
+     * difference) from cache and use it as a placeholder until the tile has been loaded.
+     * @param cache Tile cache
      */
     public void loadPlaceholderFromCache(TileCache cache) {
-        BufferedImage tmpImage = new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_RGB);
-        Graphics2D g = (Graphics2D) tmpImage.getGraphics();
-        // g.drawImage(image, 0, 0, null);
+        /*
+         *  use LazyTask as creation of BufferedImage is very expensive
+         *  this way we can avoid object creation until we're sure it's needed
+         */
+        final CachedCallable<BufferedImage> tmpImage = new CachedCallable<>(new Callable<BufferedImage>() {
+            @Override
+            public BufferedImage call() throws Exception {
+                return new BufferedImage(source.getTileSize(), source.getTileSize(), BufferedImage.TYPE_INT_RGB);
+            }
+        });
+
         for (int zoomDiff = 1; zoomDiff < 5; zoomDiff++) {
             // first we check if there are already the 2^x tiles
             // of a higher detail level
-            int zoom_high = zoom + zoomDiff;
-            if (zoomDiff < 3 && zoom_high <= JMapViewer.MAX_ZOOM) {
+            int zoomHigh = zoom + zoomDiff;
+            if (zoomDiff < 3 && zoomHigh <= JMapViewer.MAX_ZOOM) {
                 int factor = 1 << zoomDiff;
-                int xtile_high = xtile << zoomDiff;
-                int ytile_high = ytile << zoomDiff;
-                double scale = 1.0 / factor;
-                g.setTransform(AffineTransform.getScaleInstance(scale, scale));
+                int xtileHigh = xtile << zoomDiff;
+                int ytileHigh = ytile << zoomDiff;
+                final double scale = 1.0 / factor;
+
+                /*
+                 * use LazyTask for graphics to avoid evaluation of tmpImage, until we have
+                 * something to draw
+                 */
+                CachedCallable<Graphics2D> graphics = new CachedCallable<>(new Callable<Graphics2D>() {
+                    @Override
+                    public Graphics2D call() throws Exception {
+                        Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
+                        g.setTransform(AffineTransform.getScaleInstance(scale, scale));
+                        return g;
+                    }
+                });
+
                 int paintedTileCount = 0;
                 for (int x = 0; x < factor; x++) {
                     for (int y = 0; y < factor; y++) {
-                        Tile tile = cache.getTile(source, xtile_high + x, ytile_high + y, zoom_high);
+                        Tile tile = cache.getTile(source, xtileHigh + x, ytileHigh + y, zoomHigh);
                         if (tile != null && tile.isLoaded()) {
                             paintedTileCount++;
-                            tile.paint(g, x * source.getTileSize(), y * source.getTileSize());
+                            tile.paint(graphics.call(), x * source.getTileSize(), y * source.getTileSize());
                         }
                     }
                 }
                 if (paintedTileCount == factor * factor) {
-                    image = tmpImage;
+                    image = tmpImage.call();
                     return;
                 }
             }
 
-            int zoom_low = zoom - zoomDiff;
-            if (zoom_low >= JMapViewer.MIN_ZOOM) {
-                int xtile_low = xtile >> zoomDiff;
-                int ytile_low = ytile >> zoomDiff;
-                int factor = (1 << zoomDiff);
-                double scale = factor;
-                AffineTransform at = new AffineTransform();
-                int translate_x = (xtile % factor) * source.getTileSize();
-                int translate_y = (ytile % factor) * source.getTileSize();
-                at.setTransform(scale, 0, 0, scale, -translate_x, -translate_y);
-                g.setTransform(at);
-                Tile tile = cache.getTile(source, xtile_low, ytile_low, zoom_low);
+            int zoomLow = zoom - zoomDiff;
+            if (zoomLow >= JMapViewer.MIN_ZOOM) {
+                int xtileLow = xtile >> zoomDiff;
+                int ytileLow = ytile >> zoomDiff;
+                final int factor = 1 << zoomDiff;
+                final double scale = factor;
+                CachedCallable<Graphics2D> graphics = new CachedCallable<>(new Callable<Graphics2D>() {
+                    @Override
+                    public Graphics2D call() throws Exception {
+                        Graphics2D g = (Graphics2D) tmpImage.call().getGraphics();
+                        AffineTransform at = new AffineTransform();
+                        int translateX = (xtile % factor) * source.getTileSize();
+                        int translateY = (ytile % factor) * source.getTileSize();
+                        at.setTransform(scale, 0, 0, scale, -translateX, -translateY);
+                        g.setTransform(at);
+                        return g;
+                    }
+
+                });
+
+                Tile tile = cache.getTile(source, xtileLow, ytileLow, zoomLow);
                 if (tile != null && tile.isLoaded()) {
-                    tile.paint(g, 0, 0);
-                    image = tmpImage;
+                    tile.paint(graphics.call(), 0, 0);
+                    image = tmpImage.call();
                     return;
                 }
             }
@@ -235,7 +292,6 @@ public class Tile {
         g.drawImage(image, x, y, width, height, null);
     }
 
-
     @Override
     public String toString() {
         return "Tile " + key;
@@ -277,6 +333,9 @@ public class Tile {
             return false;
         if (zoom != other.zoom)
             return false;
+        if (!getTileSource().equals(other.getTileSource())) {
+            return false;
+        }
         return true;
     }
 
@@ -344,7 +403,7 @@ public class Tile {
      *
      * @return metadata of the tile
      */
-    public Map<String,String> getMetadata() {
+    public Map<String, String> getMetadata() {
         if (metadata == null) {
             metadata = new HashMap<>();
         }
diff --git a/src/org/openstreetmap/gui/jmapviewer/TileController.java b/src/org/openstreetmap/gui/jmapviewer/TileController.java
index 2e6e89b..efd2287 100644
--- a/src/org/openstreetmap/gui/jmapviewer/TileController.java
+++ b/src/org/openstreetmap/gui/jmapviewer/TileController.java
@@ -12,7 +12,7 @@ public class TileController {
     protected TileCache tileCache;
     protected TileSource tileSource;
 
-    JobDispatcher jobDispatcher;
+    protected JobDispatcher jobDispatcher;
 
     public TileController(TileSource source, TileCache tileCache, TileLoaderListener listener) {
         this.tileSource = source;
@@ -32,7 +32,7 @@ public class TileController {
      *         was not found in the cache.
      */
     public Tile getTile(int tilex, int tiley, int zoom) {
-        int max = (1 << zoom);
+        int max = 1 << zoom;
         if (tilex < 0 || tilex >= max || tiley < 0 || tiley >= max)
             return null;
         Tile tile = tileCache.getTile(tileSource, tilex, tiley, zoom);
diff --git a/src/org/openstreetmap/gui/jmapviewer/TileXY.java b/src/org/openstreetmap/gui/jmapviewer/TileXY.java
new file mode 100644
index 0000000..15f3a4f
--- /dev/null
+++ b/src/org/openstreetmap/gui/jmapviewer/TileXY.java
@@ -0,0 +1,57 @@
+// License: GPL. For details, see Readme.txt file.
+package org.openstreetmap.gui.jmapviewer;
+
+/**
+ * @author w
+ *
+ */
+public class TileXY {
+    /**
+     * x index of the tile (horizontal)
+     */
+    private final double x;
+
+    /**
+     * y number of the tile (vertical)
+     */
+    private final double y;
+
+    /**
+     * Returns an instance of coordinates.
+     *
+     * @param d number of the tile
+     * @param e number of the tile
+     */
+    public TileXY(double d, double e) {
+        this.x = d;
+        this.y = e;
+    }
+
+    /**
+     * @return x index of the tile as integer
+     */
+    public int getXIndex() {
+        return x < 0 ? (int) Math.ceil(x) : (int) Math.floor(x);
+    }
+
+    /**
+     * @return y index of the tile as integer
+     */
+    public int getYIndex() {
+        return y < 0 ? (int) Math.ceil(y) : (int) Math.floor(y);
+    }
+
+    /**
+     * @return x index as double, might be non integral, when the point is not topleft corner of the tile
+     */
+    public double getX() {
+        return x;
+    }
+
+    /**
+     * @return y index as double, might be non integral, when the point is not topleft corner of the tile
+     */
+    public double getY() {
+        return y;
+    }
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java
index 32acde0..fac15f1 100644
--- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java
+++ b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeData.java
@@ -15,30 +15,38 @@ public class CheckBoxNodeData {
     public CheckBoxNodeData(final AbstractLayer layer) {
         this.layer = layer;
     }
+
     public CheckBoxNodeData(final String txt) {
         this(new LayerGroup(txt));
     }
+
     public CheckBoxNodeData(final String txt, final Boolean selected) {
         this(new LayerGroup(txt));
         layer.setVisible(selected);
     }
+
     public Boolean isSelected() {
             return layer.isVisible();
     }
+
     public void setSelected(final Boolean newValue) {
         layer.setVisible(newValue);
     }
+
     public String getText() {
             return layer.getName();
     }
+
     public AbstractLayer getAbstractLayer() {
         return layer;
-}
+    }
+
     public void setAbstractLayer(final AbstractLayer layer) {
             this.layer = layer;
     }
+
     @Override
     public String toString() {
             return getClass().getSimpleName() + "[" + getText() + "/" + isSelected() + "]";
     }
-}
\ No newline at end of file
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
index e7e4e7b..d1c7f16 100644
--- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
+++ b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeEditor.java
@@ -52,9 +52,11 @@ public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
             return data;
         }
     }*/
-    public void addNodeListener(MouseAdapter listener){
+
+    public void addNodeListener(MouseAdapter listener) {
         renderer.addNodeListener(listener);
     }
+
     @Override
     public boolean isCellEditable(final EventObject event) {
         if (!(event instanceof MouseEvent)) return false;
@@ -75,8 +77,7 @@ public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
     @Override
     public Component getTreeCellEditorComponent(final JTree tree,
         final Object value, final boolean selected, final boolean expanded,
-        final boolean leaf, final int row)
-    {
+        final boolean leaf, final int row) {
 
         final Component editor =
             renderer.getTreeCellRendererComponent(tree, value, true, expanded, leaf,
@@ -99,4 +100,4 @@ public class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEd
 
         return editor;
     }
-}
\ No newline at end of file
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
index 4fa42a7..ce04747 100644
--- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
+++ b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodePanel.java
@@ -26,24 +26,28 @@ public class CheckBoxNodePanel extends JPanel {
         add(check, BorderLayout.WEST);
         add(label, BorderLayout.CENTER);
     }
-    public void setSelected(Boolean bool){
-        if(bool==null){
+
+    public void setSelected(Boolean bool) {
+        if (bool == null) {
             check.getModel().setPressed(true);
             check.getModel().setArmed(true);
-        }else{
+        } else {
             check.setSelected(bool.booleanValue());
             check.getModel().setArmed(false);
         }
     }
+
     public CheckBoxNodeData getData() {
         data.setSelected(check.isSelected());
         return data;
     }
+
     public void setData(CheckBoxNodeData data) {
         this.data = data;
         label.setText(data.getText());
     }
+
     public JLabel getLabel() {
         return label;
     }
-}
\ No newline at end of file
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java
index 29739c1..b534788 100644
--- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java
+++ b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxNodeRenderer.java
@@ -4,21 +4,14 @@ package org.openstreetmap.gui.jmapviewer.checkBoxTree;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Font;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
 
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
 import javax.swing.JTree;
 import javax.swing.UIManager;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.DefaultTreeCellRenderer;
 import javax.swing.tree.TreeCellRenderer;
 
-import org.openstreetmap.gui.jmapviewer.AbstractLayer;
-import org.openstreetmap.gui.jmapviewer.LayerGroup;
-
 /**
  * Renderer for checkBox Tree
  * 
@@ -28,13 +21,14 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
 
     private final CheckBoxNodePanel panel = new CheckBoxNodePanel();
     private final DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
-    private final Color selectionForeground, selectionBackground;
-    private final Color textForeground, textBackground;
-
-    protected CheckBoxNodePanel getPanel() {
-        return panel;
-    }
-
+    private final Color selectionForeground;
+    private final Color selectionBackground;
+    private final Color textForeground;
+    private final Color textBackground;
+
+    /**
+     * Constructs a new {@code CheckBoxNodeRenderer}.
+     */
     public CheckBoxNodeRenderer() {
         final Font fontValue = UIManager.getFont("Tree.font");
         if (fontValue != null) panel.getLabel().setFont(fontValue);
@@ -48,16 +42,21 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
         textForeground = UIManager.getColor("Tree.textForeground");
         textBackground = UIManager.getColor("Tree.textBackground");
     }
-    public void addNodeListener(MouseAdapter listener){
+
+    protected CheckBoxNodePanel getPanel() {
+        return panel;
+    }
+
+    public void addNodeListener(MouseAdapter listener) {
         panel.addMouseListener(listener);
     }
+
     // -- TreeCellRenderer methods --
 
     @Override
     public Component getTreeCellRendererComponent(final JTree tree,
         final Object value, final boolean selected, final boolean expanded,
-        final boolean leaf, final int row, final boolean hasFocus)
-    {
+        final boolean leaf, final int row, final boolean hasFocus) {
         CheckBoxNodeData data = null;
         if (value instanceof DefaultMutableTreeNode) {
             final DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
@@ -71,7 +70,7 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
         //    tree.convertValueToText(value, selected, expanded, leaf, row, false);
         //panel.label.setText(stringValue);
 
-        panel.setSelected(false);
+        panel.setSelected(Boolean.FALSE);
 
         panel.setEnabled(tree.isEnabled());
 
@@ -80,8 +79,7 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
             panel.setBackground(selectionBackground);
             panel.getLabel().setForeground(selectionForeground);
             panel.getLabel().setBackground(selectionBackground);
-        }
-        else {
+        } else {
             panel.setForeground(textForeground);
             panel.setBackground(textBackground);
             panel.getLabel().setForeground(textForeground);
@@ -100,11 +98,12 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
 
         return panel;
     }
+/*
     private JPopupMenu createPopupMenu(final AbstractLayer layer) {
         JMenuItem menuItem;
  
         //Create the popup menu.
-        if(layer.isVisibleTexts()) menuItem = new JMenuItem("hide texts");
+        if (layer.isVisibleTexts()) menuItem = new JMenuItem("hide texts");
         else menuItem = new JMenuItem("show texts");
         JPopupMenu popup = new JPopupMenu();
         popup.add(menuItem);
@@ -117,11 +116,16 @@ public class CheckBoxNodeRenderer implements TreeCellRenderer{
  
         return popup;
     }
-    private void setVisibleTexts(AbstractLayer layer, boolean visible){
+
+    private void setVisibleTexts(AbstractLayer layer, boolean visible) {
         layer.setVisibleTexts(visible);
-        if(layer instanceof LayerGroup){
-            LayerGroup group = (LayerGroup)layer;
-            if(group.getLayers()!=null) for(AbstractLayer al: group.getLayers()) setVisibleTexts(al, visible);
+        if (layer instanceof LayerGroup) {
+            LayerGroup group = (LayerGroup) layer;
+            if (group.getLayers() != null)
+                for (AbstractLayer al : group.getLayers()) {
+                    setVisibleTexts(al, visible);
+                }
         }
     }
-}
\ No newline at end of file
+*/
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java
index 5167860..1a2327d 100644
--- a/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java
+++ b/src/org/openstreetmap/gui/jmapviewer/checkBoxTree/CheckBoxTree.java
@@ -20,25 +20,28 @@ import org.openstreetmap.gui.jmapviewer.LayerGroup;
 
 /**
  * JTree for checkBox Tree Layers
- * 
+ *
  * @author galo
  */
 public class CheckBoxTree extends JTree{
     /** Serial Version UID */
     private static final long serialVersionUID = 6943401106938034256L;
-    
+
     private final CheckBoxNodeEditor editor;
 
-    public CheckBoxTree(AbstractLayer layer){
+    public CheckBoxTree(AbstractLayer layer) {
         this(new CheckBoxNodeData(layer));
     }
-    public CheckBoxTree(String rootName){
+
+    public CheckBoxTree(String rootName) {
         this(new CheckBoxNodeData(rootName));
     }
-    public CheckBoxTree(CheckBoxNodeData root ){
+
+    public CheckBoxTree(CheckBoxNodeData root) {
         this(new DefaultMutableTreeNode(root));
     }
-    public CheckBoxTree(DefaultMutableTreeNode node){
+
+    public CheckBoxTree(DefaultMutableTreeNode node) {
         super(new DefaultTreeModel(node));
 
         final CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
@@ -47,17 +50,17 @@ public class CheckBoxTree extends JTree{
         editor = new CheckBoxNodeEditor(this);
         setCellEditor(editor);
         setEditable(true);
-        
+
         // listen for changes in the model (including check box toggles)
         getModel().addTreeModelListener(new TreeModelListener() {
             @Override
             public void treeNodesChanged(final TreeModelEvent e) {
-                DefaultTreeModel model = (DefaultTreeModel)e.getSource();
+                DefaultTreeModel model = (DefaultTreeModel) e.getSource();
                 Object[] nodes = e.getChildren();
                 DefaultMutableTreeNode node;
-                if(nodes==null||nodes.length==0){
+                if (nodes == null || nodes.length == 0) {
                     node = node(model.getRoot());
-                }else{
+                } else {
                     node = node(nodes[0]);
                 }
                 nodeChanged(node);
@@ -80,11 +83,13 @@ public class CheckBoxTree extends JTree{
             }
         });
     }
-    public void addNodeListener(MouseAdapter listener){
+
+    public void addNodeListener(MouseAdapter listener) {
         editor.addNodeListener(listener);
     }
-    public static void main(final String args[]) {
-        final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new CheckBoxNodeData("Root",true));
+
+    public static void main(final String[] args) {
+        final DefaultMutableTreeNode root = new DefaultMutableTreeNode(new CheckBoxNodeData("Root", Boolean.TRUE));
 
         final DefaultMutableTreeNode accessibility =
             add(root, "Accessibility", true);
@@ -101,8 +106,8 @@ public class CheckBoxTree extends JTree{
         root.add(browsing);
 
         final CheckBoxTree tree = new CheckBoxTree(root);
-        ((DefaultMutableTreeNode)tree.getModel().getRoot()).add(new DefaultMutableTreeNode(new CheckBoxNodeData("gggg", null)));
-        ((DefaultTreeModel)tree.getModel()).reload();
+        ((DefaultMutableTreeNode) tree.getModel().getRoot()).add(new DefaultMutableTreeNode(new CheckBoxNodeData("gggg", null)));
+        ((DefaultTreeModel) tree.getModel()).reload();
         // listen for changes in the selection
         tree.addTreeSelectionListener(new TreeSelectionListener() {
             @Override
@@ -118,76 +123,93 @@ public class CheckBoxTree extends JTree{
         frame.setSize(300, 150);
         frame.setVisible(true);
     }
-    private static Boolean childStatus(DefaultMutableTreeNode node){
+
+    private static Boolean childStatus(DefaultMutableTreeNode node) {
         Boolean status = data(node.getChildAt(0)).isSelected();
-        for(int i=1; i<node.getChildCount()&&status!=null; i++){
-            if(status != data(node.getChildAt(i)).isSelected()) return null;
+        for (int i = 1; i < node.getChildCount() && status != null; i++) {
+            if (!status.equals(
+                    data(node.getChildAt(i)).isSelected()
+                    ))
+                return null;
         }
         return status;
     }
-    private static void changeParents(DefaultMutableTreeNode node){
-        if(node!=null){
+
+    private static void changeParents(DefaultMutableTreeNode node) {
+        if (node != null) {
             DefaultMutableTreeNode parent = node(node.getParent());
-            if(parent!=null){
+            if (parent != null) {
                 CheckBoxNodeData dataParent = data(parent);
                 Boolean childStatus = childStatus(parent);
-                if(dataParent.isSelected()!=childStatus){
+                if (childStatus != null && !childStatus.equals(dataParent.isSelected())) {
                     dataParent.setSelected(childStatus);
                     changeParents(parent);
                 }
             }
         }
     }
-    private static void nodeChanged(DefaultMutableTreeNode node){
-        if(node!=null){
+
+    private static void nodeChanged(DefaultMutableTreeNode node) {
+        if (node != null) {
             changeParents(node);
             setChildrens(node, data(node).isSelected());
         }
     }
-    private static void setChildrens(DefaultMutableTreeNode node, Boolean value){
-        for(int i=0; i<node.getChildCount(); i++){
+
+    private static void setChildrens(DefaultMutableTreeNode node, Boolean value) {
+        for (int i = 0; i < node.getChildCount(); i++) {
             DefaultMutableTreeNode childNode = node(node.getChildAt(i));
-            if (data(childNode).isSelected() !=data(node).isSelected()){
+            if (!data(childNode).isSelected().equals(data(node).isSelected())) {
                 data(childNode).setSelected(data(node).isSelected());
                 setChildrens(childNode, value);
             }
         }
     }
-    public DefaultMutableTreeNode rootNode(){
+
+    public DefaultMutableTreeNode rootNode() {
         return node(getModel().getRoot());
     }
-    public LayerGroup rootLayer(){
-        return (LayerGroup)rootData().getAbstractLayer();
+
+    public LayerGroup rootLayer() {
+        return (LayerGroup) rootData().getAbstractLayer();
     }
-    public CheckBoxNodeData rootData(){
+
+    public CheckBoxNodeData rootData() {
         return data(rootNode());
     }
-    private static DefaultMutableTreeNode node(Object node){
-        return (DefaultMutableTreeNode)node;
+
+    private static DefaultMutableTreeNode node(Object node) {
+        return (DefaultMutableTreeNode) node;
     }
-    public static CheckBoxNodeData data(DefaultMutableTreeNode node){
-        return node==null?null:(CheckBoxNodeData)node.getUserObject();
+
+    public static CheckBoxNodeData data(DefaultMutableTreeNode node) {
+        return node == null ? null : (CheckBoxNodeData) node.getUserObject();
     }
-    private static CheckBoxNodeData data(Object node){
+
+    private static CheckBoxNodeData data(Object node) {
         return data(node(node));
     }
-    private static DefaultMutableTreeNode add(final DefaultMutableTreeNode parent, final String text, final boolean checked){
+
+    private static DefaultMutableTreeNode add(final DefaultMutableTreeNode parent, final String text, final boolean checked) {
         final CheckBoxNodeData data = new CheckBoxNodeData(text, checked);
         final DefaultMutableTreeNode node = new DefaultMutableTreeNode(data);
         parent.add(node);
         return node;
     }
-    public static CheckBoxNodeData createNodeData(AbstractLayer layer){
+
+    public static CheckBoxNodeData createNodeData(AbstractLayer layer) {
         return new CheckBoxNodeData(layer);
     }
-    public static DefaultMutableTreeNode createNode(AbstractLayer layer){
+
+    public static DefaultMutableTreeNode createNode(AbstractLayer layer) {
         return new DefaultMutableTreeNode(createNodeData(layer));
     }
-    /*public DefaultMutableTreeNode addLayerGroup(LayerGroup group){
-        if(group!=null){
-            if(group.getParent()==null){
+
+    /*public DefaultMutableTreeNode addLayerGroup(LayerGroup group) {
+        if (group != null){
+            if (group.getParent() == null){
                 return add(rootNode(), group);
-            }else{
+            } else {
                 DefaultMutableTreeNode parentGroup = searchNode(group.getParent());
                 if(parentGroup==null) parentGroup = addLayerGroup(group.getParent());
                 DefaultMutableTreeNode node = add(parentGroup, group);
@@ -195,44 +217,50 @@ public class CheckBoxTree extends JTree{
             }
         }else return null;
     }*/
-    public Layer addLayer(String name){
+
+    public Layer addLayer(String name) {
         Layer layer = new Layer(name);
         addLayer(layer);
         return layer;
     }
-    public DefaultMutableTreeNode addLayer(AbstractLayer layer){
-        if (layer!=null){
+
+    public DefaultMutableTreeNode addLayer(AbstractLayer layer) {
+        if (layer != null) {
             DefaultMutableTreeNode parent;
-            if(layer.getParent()==null){
+            if (layer.getParent() == null) {
                 rootLayer().add(layer);
                 parent = rootNode();
-            }else{
+            } else {
                 parent = searchNode(layer.getParent());
-                if(parent==null) parent=addLayer(layer.getParent());
+                if (parent == null)
+                    parent = addLayer(layer.getParent());
             }
             return add(parent, layer);
-        }else return null;
+        } else return null;
     }
-    public DefaultMutableTreeNode add(DefaultMutableTreeNode parent, final AbstractLayer layer){
+
+    public DefaultMutableTreeNode add(DefaultMutableTreeNode parent, final AbstractLayer layer) {
         layer.setVisible(data(parent).isSelected());
-        DefaultMutableTreeNode node = createNode(layer); 
+        DefaultMutableTreeNode node = createNode(layer);
         parent.add(node);
-        ((DefaultTreeModel)getModel()).reload();
+        ((DefaultTreeModel) getModel()).reload();
         //System.out.println("Created node "+layer+" upper of "+data(parent));
         return node;
     }
-    public DefaultMutableTreeNode searchNode(AbstractLayer layer){
+
+    public DefaultMutableTreeNode searchNode(AbstractLayer layer) {
         return searchNode(rootNode(), layer);
     }
-    public DefaultMutableTreeNode searchNode(DefaultMutableTreeNode node, AbstractLayer layer){
+
+    public DefaultMutableTreeNode searchNode(DefaultMutableTreeNode node, AbstractLayer layer) {
         CheckBoxNodeData data = CheckBoxTree.data(node);
-        if(data.getAbstractLayer() == layer) return node;
-        else{
+        if (data.getAbstractLayer() == layer) return node;
+        else {
             DefaultMutableTreeNode found = null;
-            for(int i=0; i<node.getChildCount() && found==null; i++){
-                found = searchNode((DefaultMutableTreeNode)node.getChildAt(i), layer);
+            for (int i = 0; i < node.getChildCount() && found == null; i++) {
+                found = searchNode((DefaultMutableTreeNode) node.getChildAt(i), layer);
             }
             return found;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java
index 24d25e6..9f62f3d 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/Attributed.java
@@ -3,8 +3,6 @@ package org.openstreetmap.gui.jmapviewer.interfaces;
 
 import java.awt.Image;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
-
 public interface Attributed {
     /**
      * @return True if the tile source requires attribution in text or image form.
@@ -17,7 +15,7 @@ public interface Attributed {
      * @param topLeft The top left of the bounding box for attribution.
      * @return Attribution text for the image source.
      */
-    String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight);
+    String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight);
 
     /**
      * @return The URL to open when the user clicks the attribution text.
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/CachedTileLoader.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/CachedTileLoader.java
index bcf6fcf..4b41ec8 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/CachedTileLoader.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/CachedTileLoader.java
@@ -5,5 +5,5 @@ package org.openstreetmap.gui.jmapviewer.interfaces;
  * Interface that allow cleaning the tile cache without specifying exact type of loader
  */
 public interface CachedTileLoader {
-    public void clearCache(TileSource source);
+    void clearCache(TileSource source);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java
index 1b14153..47ae9b0 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/ICoordinate.java
@@ -2,8 +2,12 @@
 package org.openstreetmap.gui.jmapviewer.interfaces;
 
 public interface ICoordinate {
-    public double getLat();
-    public void setLat(double lat);
-    public double getLon();
-    public void setLon(double lon);
+
+    double getLat();
+
+    void setLat(double lat);
+
+    double getLon();
+
+    void setLon(double lon);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/JMapViewerEventListener.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/JMapViewerEventListener.java
index 0064aeb..8642d1b 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/JMapViewerEventListener.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/JMapViewerEventListener.java
@@ -13,5 +13,5 @@ import org.openstreetmap.gui.jmapviewer.events.JMVCommandEvent;
  *
  */
 public interface JMapViewerEventListener extends EventListener {
-    public void processCommand(JMVCommandEvent command);
+    void processCommand(JMVCommandEvent command);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapMarker.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapMarker.java
index 2a1968f..a138b1c 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapMarker.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapMarker.java
@@ -16,39 +16,45 @@ import org.openstreetmap.gui.jmapviewer.JMapViewer;
  */
 public interface MapMarker extends MapObject, ICoordinate{
 
-    public static enum STYLE {FIXED, VARIABLE}
+    enum STYLE {
+        FIXED,
+        VARIABLE
+    }
 
     /**
      * @return Latitude and Longitude of the map marker position
      */
-    public Coordinate getCoordinate();
+    Coordinate getCoordinate();
+
     /**
      * @return Latitude of the map marker position
      */
-    public double getLat();
+    @Override
+    double getLat();
 
     /**
      * @return Longitude of the map marker position
      */
-    public double getLon();
+    @Override
+    double getLon();
 
     /**
      * @return Radius of the map marker position
      */
-    public double getRadius();
+    double getRadius();
 
     /**
      * @return Style of the map marker
      */
-    public STYLE getMarkerStyle();
+    STYLE getMarkerStyle();
 
     /**
      * Paints the map marker on the map. The <code>position</code> specifies the
      * coordinates within <code>g</code>
      *
-     * @param g
-     * @param position
-     * @param radio
+     * @param g graphics
+     * @param position coordinates
+     * @param radius radius
      */
-    public void paint(Graphics g, Point position, int radio);
+    void paint(Graphics g, Point position, int radius);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java
index 71ca133..213fbd5 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapObject.java
@@ -10,14 +10,23 @@ import org.openstreetmap.gui.jmapviewer.Style;
 
 public interface MapObject {
 
-    public Layer getLayer();
-    public void setLayer(Layer layer);
-    public Style getStyle();
-    public Style getStyleAssigned();
-    public Color getColor();
-    public Color getBackColor();
-    public Stroke getStroke();
-    public Font getFont();
-    public String getName();
-    public boolean isVisible();
+    Layer getLayer();
+
+    void setLayer(Layer layer);
+
+    Style getStyle();
+
+    Style getStyleAssigned();
+
+    Color getColor();
+
+    Color getBackColor();
+
+    Stroke getStroke();
+
+    Font getFont();
+
+    String getName();
+
+    boolean isVisible();
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java
index 73b1259..a212497 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapPolygon.java
@@ -9,30 +9,30 @@ import java.util.List;
 /**
  * Interface to be implemented by polygons that can be displayed on the map.
  *
- * @author Vincent
+ * @author Vincent Privat
  */
 public interface MapPolygon extends MapObject{
 
     /**
      * @return Latitude/Longitude of each point of polygon
      */
-    public List<? extends ICoordinate> getPoints();
+    List<? extends ICoordinate> getPoints();
 
     /**
-     * Paints the map rectangle on the map. The <code>points</code>
+     * Paints the map polygon on the map. The <code>points</code>
      * are specifying the coordinates within <code>g</code>
      *
-     * @param g
-     * @param points
+     * @param g graphics
+     * @param points list of points defining the polygon to draw
      */
-    public void paint(Graphics g, List<Point> points);
+    void paint(Graphics g, List<Point> points);
 
     /**
-     * Paints the map rectangle on the map. The <code>polygon</code>
+     * Paints the map polygon on the map. The <code>polygon</code>
      * is specifying the coordinates within <code>g</code>
      *
-     * @param g
-     * @param polygon
+     * @param g graphics
+     * @param polygon polygon to draw
      */
-    public void paint(Graphics g, Polygon polygon);
+    void paint(Graphics g, Polygon polygon);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java
index 0d11c11..e566767 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/MapRectangle.java
@@ -19,12 +19,12 @@ public interface MapRectangle extends MapObject{
     /**
      * @return Latitude/Longitude of top left of rectangle
      */
-    public Coordinate getTopLeft();
+    Coordinate getTopLeft();
 
     /**
      * @return Latitude/Longitude of bottom right of rectangle
      */
-    public Coordinate getBottomRight();
+    Coordinate getBottomRight();
 
     /**
      * Paints the map rectangle on the map. The <code>topLeft</code> and
@@ -34,5 +34,5 @@ public interface MapRectangle extends MapObject{
      * @param topLeft lop left edge of painting region
      * @param bottomRight bottom right edge of painting region
      */
-    public void paint(Graphics g, Point topLeft, Point bottomRight);
+    void paint(Graphics g, Point topLeft, Point bottomRight);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java
new file mode 100644
index 0000000..1037c9f
--- /dev/null
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TemplatedTileSource.java
@@ -0,0 +1,18 @@
+// License: GPL. For details, see Readme.txt file.
+package org.openstreetmap.gui.jmapviewer.interfaces;
+
+import java.util.Map;
+
+/**
+ * Interface for template tile sources, @see TemplatedTMSTileSource
+ *
+ * @author Wiktor Niesiobędzki
+ * @since 1.10
+ */
+public interface TemplatedTileSource extends TileSource {
+    /**
+     *
+     * @return headers to be sent with http requests
+     */
+    Map<String, String> getHeaders();
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
index 209d2fa..c31a7ac 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileCache.java
@@ -27,7 +27,7 @@ public interface TileCache {
      * @return the requested tile or <code>null</code> if the tile is not
      *         present in the cache
      */
-    public Tile getTile(TileSource source, int x, int y, int z);
+    Tile getTile(TileSource source, int x, int y, int z);
 
     /**
      * Adds a tile to the cache. How long after adding a tile can be retrieved
@@ -36,15 +36,15 @@ public interface TileCache {
      *
      * @param tile the tile to be added
      */
-    public void addTile(Tile tile);
+    void addTile(Tile tile);
 
     /**
      * @return the number of tiles hold by the cache
      */
-    public int getTileCount();
+    int getTileCount();
 
     /**
      * Clears the cache deleting all tiles from memory.
      */
-    public void clear();
+    void clear();
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java
index 603d354..94a5a83 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileClearController.java
@@ -14,4 +14,4 @@ public interface TileClearController {
     void fileDeleted(File file);
 
     void clearFinished();
-}
\ No newline at end of file
+}
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java
index f546b48..7a5ad54 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileJob.java
@@ -16,7 +16,7 @@ public interface TileJob extends Runnable {
      *
      * @return {@link Tile} to be handled
      */
-    public Tile getTile();
+    Tile getTile();
 
     /**
      * submits download job to backend.
@@ -25,7 +25,7 @@ public interface TileJob extends Runnable {
 
     /**
      * submits download job to backend.
-     * @param force true if the load should skip all the caches (local & remote)
+     * @param force true if the load should skip all the caches (local & remote)
      */
     void submit(boolean force);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java
index 723d707..60fd704 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoader.java
@@ -19,5 +19,5 @@ public interface TileLoader {
      * @return {@link TileJob} implementation that performs the desired load
      *          action.
      */
-    public TileJob createTileLoaderJob(Tile tile);
+    TileJob createTileLoaderJob(Tile tile);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java
index 133c27a..8793611 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java
@@ -12,5 +12,5 @@ public interface TileLoaderListener {
      * @param tile The tile
      * @param success {@code true} if the tile has been loaded successfully, {@code false} otherwise
      */
-    public void tileLoadingFinished(Tile tile, boolean success);
+    void tileLoadingFinished(Tile tile, boolean success);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
index ec509c0..64aa6c4 100644
--- a/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
@@ -1,11 +1,14 @@
 // License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.interfaces;
 
+import java.awt.Point;
 import java.io.IOException;
 import java.util.List;
 import java.util.Map;
 
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.Tile;
+import org.openstreetmap.gui.jmapviewer.TileXY;
 
 /**
  *
@@ -34,8 +37,10 @@ public interface TileSource extends Attributed {
      * mechanisms.</li>
      * </ul>
      *
+     * @deprecated not used anymore
      */
-    public enum TileUpdate {
+    @Deprecated
+    enum TileUpdate {
         IfNoneMatch, ETag, IfModifiedSince, LastModified, None
     }
 
@@ -83,82 +88,224 @@ public interface TileSource extends Attributed {
     /**
      * Constructs the tile url.
      *
-     * @param zoom
-     * @param tilex
-     * @param tiley
+     * @param zoom zoom level
+     * @param tilex X coordinate
+     * @param tiley Y coordinate
      * @return fully qualified url for downloading the specified tile image
+     * @throws IOException if any I/O error occurs
      */
     String getTileUrl(int zoom, int tilex, int tiley) throws IOException;
 
     /**
-     * Specifies the tile image type. For tiles rendered by Mapnik or
-     * Osmarenderer this is usually <code>"png"</code>.
+     * Creates tile identifier that is unique among all tile sources, but the same tile will always
+     * get the same identifier. Used for creation of cache key.
      *
-     * @return file extension of the tile image type
+     * @param zoom zoom level
+     * @param tilex X coordinate
+     * @param tiley Y coordinate
+     * @return tile identifier
      */
-    String getTileType();
+    String getTileId(int zoom, int tilex, int tiley);
 
     /**
      * Specifies how large each tile is.
-     * @return The size of a single tile in pixels.
+     * @return The size of a single tile in pixels. -1 if default size should be used
      */
     int getTileSize();
 
     /**
+     * @return default tile size, for this tile source
+     * TODO: @since
+     */
+    int getDefaultTileSize();
+
+    /**
      * Gets the distance using Spherical law of cosines.
-     *  @return the distance, m.
+     * @param la1 latitude of first point
+     * @param lo1 longitude of first point
+     * @param la2 latitude of second point
+     * @param lo2 longitude of second point
+     * @return the distance betwen first and second point, in m.
      */
     double getDistance(double la1, double lo1, double la2, double lo2);
 
     /**
      * Transform longitude to pixelspace.
+     * @param aLongitude longitude
+     * @param aZoomlevel zoom level
      * @return [0..2^Zoomlevel*TILE_SIZE[
+     * @deprecated use {@link #latLonToXY(double, double, int)} instead
      */
-    int LonToX(double aLongitude, int aZoomlevel);
+    @Deprecated
+    int lonToX(double aLongitude, int aZoomlevel);
 
     /**
      * Transforms latitude to pixelspace.
+     * @param aLat latitude
+     * @param aZoomlevel zoom level
      * @return [0..2^Zoomlevel*TILE_SIZE[
+     * @deprecated use {@link #latLonToXY(double, double, int)} instead
+     */
+    @Deprecated
+    int latToY(double aLat, int aZoomlevel);
+
+    /**
+     * @param lon longitude
+     * @param lat latitude
+     * @param zoom zoom level
+     * @return transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined)
      */
-    int LatToY(double aLat, int aZoomlevel);
+    Point latLonToXY(double lat, double lon, int zoom);
+
+    /**
+     * @param point point
+     * @param zoom zoom level
+     * @return transforms longitude and latitude to pixel space (as if all tiles at specified zoom level where joined)
+     */
+    Point latLonToXY(ICoordinate point, int zoom);
 
     /**
      * Transforms pixel coordinate X to longitude
+     * @param aX X coordinate
+     * @param aZoomlevel zoom level
      * @return ]-180..180[
+     * @deprecated use {@link #xyToLatLon(int, int, int)} instead
      */
+    @Deprecated
     double XToLon(int aX, int aZoomlevel);
 
     /**
      * Transforms pixel coordinate Y to latitude.
+     * @param aY Y coordinate
+     * @param aZoomlevel zoom level
      * @return [MIN_LAT..MAX_LAT]
+     * @deprecated use {@link #xyToLatLon(int, int, int)} instead
      */
+    @Deprecated
     double YToLat(int aY, int aZoomlevel);
 
     /**
+     * @param point point
+     * @param zoom zoom level
+     * @return WGS84 Coordinates of given point
+     */
+    ICoordinate xyToLatLon(Point point, int zoom);
+
+    /**
+     *
+     * @param x X coordinate
+     * @param y Y coordinate
+     * @param zoom zoom level
+     * @return WGS84 Coordinates of given point
+     */
+    ICoordinate xyToLatLon(int x, int y, int zoom);
+
+    /**
      * Transforms longitude to X tile coordinate.
+     * @param lon longitude
+     * @param zoom zoom level
      * @return [0..2^Zoomlevel[
+     * @deprecated use {@link #latLonToTileXY(double, double, int)} instead
      */
+    @Deprecated
     double lonToTileX(double lon, int zoom);
 
     /**
      * Transforms latitude to Y tile coordinate.
+     * @param lat latitude
+     * @param zoom zoom level
      * @return [0..2^Zoomlevel[
+     * @deprecated use {@link #latLonToTileXY(double, double, int)} instead
      */
+    @Deprecated
     double latToTileY(double lat, int zoom);
 
     /**
+     * @param lon longitude
+     * @param lat latitude
+     * @param zoom zoom level
+     * @return x and y tile indices
+     */
+    TileXY latLonToTileXY(double lat, double lon, int zoom);
+
+    /**
+     *
+     * @param point point
+     * @param zoom zoom level
+     * @return x and y tile indices
+     */
+    TileXY latLonToTileXY(ICoordinate point, int zoom);
+
+    /**
      * Transforms tile X coordinate to longitude.
+     * @param x X coordinate
+     * @param zoom zoom level
      * @return ]-180..180[
+     * @deprecated use {@link #tileXYToLatLon(int, int, int)} instead
      */
+    @Deprecated
     double tileXToLon(int x, int zoom);
 
     /**
      * Transforms tile Y coordinate to latitude.
+     * @param y Y coordinate
+     * @param zoom zoom level
      * @return [MIN_LAT..MAX_LAT]
+     * @deprecated use {@link #tileXYToLatLon(int, int, int)} instead
      */
+    @Deprecated
     double tileYToLat(int y, int zoom);
 
     /**
+     * @param xy X/Y coordinates
+     * @param zoom zoom level
+     * @return WGS84 coordinates of given tile
+     */
+    ICoordinate tileXYToLatLon(TileXY xy, int zoom);
+
+    /**
+     *
+     * @param tile Tile
+     * @return WGS84 coordinates of given tile
+     */
+    ICoordinate tileXYToLatLon(Tile tile);
+
+    /**
+     *
+     * @param x X coordinate
+     * @param y Y coordinate
+     * @param zoom zoom level
+     * @return WGS84 coordinates of given tile
+     */
+    ICoordinate tileXYToLatLon(int x, int y, int zoom);
+
+    /**
+     * @param zoom zoom level
+     * @return maximum X index of tile for specified zoom level
+     */
+    int getTileXMax(int zoom);
+
+    /**
+     *
+     * @param zoom zoom level
+     * @return minimum X index of tile for specified zoom level
+     */
+    int getTileXMin(int zoom);
+
+    /**
+     *
+     * @param zoom zoom level
+     * @return maximum Y index of tile for specified zoom level
+     */
+    int getTileYMax(int zoom);
+
+    /**
+     * @param zoom zoom level
+     * @return minimum Y index of tile for specified zoom level
+     */
+    int getTileYMin(int zoom);
+
+    /**
      * Determines, if the returned data from TileSource represent "no tile at this zoom level" situation. Detection
      * algorithms differ per TileSource, so each TileSource should implement each own specific way.
      *
@@ -167,7 +314,7 @@ public interface TileSource extends Attributed {
      * @param content byte array representing the data returned from the server
      * @return true, if "no tile at this zoom level" situation detected
      */
-    public boolean isNoTileAtZoom(Map<String, List<String>> headers, int statusCode, byte[] content);
+    boolean isNoTileAtZoom(Map<String, List<String>> headers, int statusCode, byte[] content);
 
     /**
      * Extracts metadata about the tile based on HTTP headers
@@ -175,5 +322,5 @@ public interface TileSource extends Attributed {
      * @param headers HTTP headers from Tile Source server
      * @return tile metadata
      */
-    public Map<String, String> getMetadata(Map<String, List<String>> headers);
+    Map<String, String> getMetadata(Map<String, List<String>> headers);
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/package.html b/src/org/openstreetmap/gui/jmapviewer/package.html
index d9b0584..9cd9c42 100644
--- a/src/org/openstreetmap/gui/jmapviewer/package.html
+++ b/src/org/openstreetmap/gui/jmapviewer/package.html
@@ -9,4 +9,4 @@ any further requirements. Therefore <b>please do not add any code that
 depends on other libraries or applications</b>. Only functions and methods
 provided by the runtime library of Java 7 should be used.</p>
 </body>
-</html>
\ No newline at end of file
+</html>
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java
index 0fc6c41..201a3ff 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractOsmTileSource.java
@@ -3,7 +3,7 @@ package org.openstreetmap.gui.jmapviewer.tilesources;
 
 import java.awt.Image;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 /**
  * Abstract class for OSM Tile sources
@@ -11,7 +11,8 @@ import org.openstreetmap.gui.jmapviewer.Coordinate;
 public abstract class AbstractOsmTileSource extends AbstractTMSTileSource {
     
     /**
-     * The OSM attribution. Must be always in line with <a href="https://www.openstreetmap.org/copyright/en">https://www.openstreetmap.org/copyright/en</a>
+     * The OSM attribution. Must be always in line with 
+     * <a href="https://www.openstreetmap.org/copyright/en">https://www.openstreetmap.org/copyright/en</a>
      */
     public static final String DEFAULT_OSM_ATTRIBUTION = "\u00a9 OpenStreetMap contributors";
     
@@ -24,7 +25,6 @@ public abstract class AbstractOsmTileSource extends AbstractTMSTileSource {
      */
     public AbstractOsmTileSource(String name, String base_url, String id) {
         super(new TileSourceInfo(name, base_url, id));
-
     }
 
     @Override
@@ -38,7 +38,7 @@ public abstract class AbstractOsmTileSource extends AbstractTMSTileSource {
     }
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return DEFAULT_OSM_ATTRIBUTION;
     }
 
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
index 50a6a7c..a2d2582 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTMSTileSource.java
@@ -1,35 +1,59 @@
 // License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
+import java.awt.Point;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.openstreetmap.gui.jmapviewer.Coordinate;
 import org.openstreetmap.gui.jmapviewer.OsmMercator;
+import org.openstreetmap.gui.jmapviewer.Tile;
+import org.openstreetmap.gui.jmapviewer.TileXY;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
+/**
+ * Class generalizing all tile based tile sources
+ *
+ * @author Wiktor Niesiobędzki
+ *
+ */
 public abstract class AbstractTMSTileSource extends AbstractTileSource {
 
     protected String name;
     protected String baseUrl;
     protected String id;
-    private Map<String, String> noTileHeaders;
-    private Map<String, String> metadataHeaders;
+    private final Map<String, String> noTileHeaders;
+    private final Map<String, String> metadataHeaders;
     protected int tileSize;
     protected OsmMercator osmMercator;
 
+    /**
+     * Creates an instance based on TileSource information
+     *
+     * @param info description of the Tile Source
+     */
     public AbstractTMSTileSource(TileSourceInfo info) {
         this.name = info.getName();
         this.baseUrl = info.getUrl();
-        if(baseUrl != null && baseUrl.endsWith("/")) {
-            baseUrl = baseUrl.substring(0,baseUrl.length()-1);
+        if (baseUrl != null && baseUrl.endsWith("/")) {
+            baseUrl = baseUrl.substring(0, baseUrl.length()-1);
         }
         this.id = info.getUrl();
         this.noTileHeaders = info.getNoTileHeaders();
         this.metadataHeaders = info.getMetadataHeaders();
         this.tileSize = info.getTileSize();
-        osmMercator = new OsmMercator(this.tileSize);
+        this.osmMercator = new OsmMercator(this.tileSize);
+    }
+
+    /**
+     * @return default tile size to use, when not set in Imagery Preferences
+     */
+    @Override
+    public int getDefaultTileSize() {
+        return OsmMercator.DEFAUL_TILE_SIZE;
     }
 
     @Override
@@ -52,17 +76,27 @@ public abstract class AbstractTMSTileSource extends AbstractTileSource {
         return 0;
     }
 
+    /**
+     * @return image extension, used for URL creation
+     */
     public String getExtension() {
         return "png";
     }
 
     /**
+     * @param zoom level of the tile
+     * @param tilex tile number in x axis
+     * @param tiley tile number in y axis
+     * @return String containg path part of URL of the tile
      * @throws IOException when subclass cannot return the tile URL
      */
     public String getTilePath(int zoom, int tilex, int tiley) throws IOException {
         return "/" + zoom + "/" + tilex + "/" + tiley + "." + getExtension();
     }
 
+    /**
+     * @return Base part of the URL of the tile source
+     */
     public String getBaseUrl() {
         return this.baseUrl;
     }
@@ -77,16 +111,14 @@ public abstract class AbstractTMSTileSource extends AbstractTileSource {
         return getName();
     }
 
-    @Override
-    public String getTileType() {
-        return "png";
-    }
-
     /*
      * Most tilesources use OsmMercator projection.
      */
     @Override
     public int getTileSize() {
+        if (tileSize <= 0) {
+            return getDefaultTileSize();
+        }
         return tileSize;
     }
 
@@ -96,43 +128,120 @@ public abstract class AbstractTMSTileSource extends AbstractTileSource {
     }
 
     @Override
-    public int LonToX(double lon, int zoom) {
-        return (int )osmMercator.LonToX(lon, zoom);
+    public int lonToX(double lon, int zoom) {
+        return (int) osmMercator.lonToX(lon, zoom);
     }
 
     @Override
-    public int LatToY(double lat, int zoom) {
-        return (int )osmMercator.LatToY(lat, zoom);
+    public int latToY(double lat, int zoom) {
+        return (int) osmMercator.latToY(lat, zoom);
+    }
+
+    @Override
+    public Point latLonToXY(double lat, double lon, int zoom) {
+        return new Point(
+                (int) osmMercator.lonToX(lon, zoom),
+                (int) osmMercator.latToY(lat, zoom)
+                );
+    }
+
+    @Override
+    public Point latLonToXY(ICoordinate point, int zoom) {
+        return latLonToXY(point.getLat(), point.getLon(), zoom);
     }
 
     @Override
     public double XToLon(int x, int zoom) {
-        return osmMercator.XToLon(x, zoom);
+        return osmMercator.xToLon(x, zoom);
     }
 
     @Override
     public double YToLat(int y, int zoom) {
-        return osmMercator.YToLat(y, zoom);
+        return osmMercator.yToLat(y, zoom);
+    }
+
+    @Override
+    public ICoordinate xyToLatLon(Point point, int zoom) {
+        return xyToLatLon(point.x, point.y, zoom);
+    }
+
+    @Override
+    public ICoordinate xyToLatLon(int x, int y, int zoom) {
+        return new Coordinate(
+                osmMercator.yToLat(y, zoom),
+                osmMercator.xToLon(x, zoom)
+                );
     }
 
     @Override
     public double latToTileY(double lat, int zoom) {
-        return osmMercator.LatToY(lat, zoom) / tileSize;
+        return osmMercator.latToY(lat, zoom) / tileSize;
     }
 
     @Override
     public double lonToTileX(double lon, int zoom) {
-        return osmMercator.LonToX(lon, zoom) / tileSize;
+        return osmMercator.lonToX(lon, zoom) / tileSize;
+    }
+
+    @Override
+    public TileXY latLonToTileXY(double lat, double lon, int zoom) {
+        return new TileXY(
+                osmMercator.lonToX(lon, zoom) / tileSize,
+                osmMercator.latToY(lat, zoom) / tileSize
+                );
+    }
+
+    @Override
+    public TileXY latLonToTileXY(ICoordinate point, int zoom) {
+        return latLonToTileXY(point.getLat(), point.getLon(), zoom);
     }
 
     @Override
     public double tileYToLat(int y, int zoom) {
-        return osmMercator.YToLat(y * tileSize, zoom);
+        return osmMercator.yToLat(y * tileSize, zoom);
     }
 
     @Override
     public double tileXToLon(int x, int zoom) {
-        return osmMercator.XToLon(x * tileSize, zoom);
+        return osmMercator.xToLon(x * tileSize, zoom);
+    }
+
+    @Override
+    public ICoordinate tileXYToLatLon(TileXY xy, int zoom) {
+        return tileXYToLatLon(xy.getXIndex(), xy.getYIndex(), zoom);
+    }
+
+    @Override
+    public ICoordinate tileXYToLatLon(Tile tile) {
+        return tileXYToLatLon(tile.getXtile(), tile.getYtile(), tile.getZoom());
+    }
+
+    @Override
+    public ICoordinate tileXYToLatLon(int x, int y, int zoom) {
+        return new Coordinate(
+                osmMercator.yToLat(y * tileSize, zoom),
+                osmMercator.xToLon(x * tileSize, zoom)
+                );
+    }
+
+    @Override
+    public int getTileXMax(int zoom) {
+        return getTileMax(zoom);
+    }
+
+    @Override
+    public int getTileXMin(int zoom) {
+        return 0;
+    }
+
+    @Override
+    public int getTileYMax(int zoom) {
+        return getTileMax(zoom);
+    }
+
+    @Override
+    public int getTileYMin(int zoom) {
+        return 0;
     }
 
     @Override
@@ -167,4 +276,13 @@ public abstract class AbstractTMSTileSource extends AbstractTileSource {
         }
         return ret;
     }
+
+    @Override
+    public String getTileId(int zoom, int tilex, int tiley) {
+        return this.baseUrl + "/" + zoom + "/" + tilex + "/" + tiley;
+    }
+
+    private static int getTileMax(int zoom) {
+        return (int) Math.pow(2.0, zoom) - 1;
+    }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java
index b41e558..185eb04 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/AbstractTileSource.java
@@ -5,10 +5,10 @@ import java.awt.Image;
 import java.util.List;
 import java.util.Map;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
 
-abstract public class AbstractTileSource implements TileSource {
+public abstract class AbstractTileSource implements TileSource {
 
     protected String attributionText;
     protected String attributionLinkURL;
@@ -23,7 +23,7 @@ abstract public class AbstractTileSource implements TileSource {
     }
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return attributionText;
     }
 
@@ -76,6 +76,7 @@ abstract public class AbstractTileSource implements TileSource {
         this.termsOfUseURL = termsOfUseURL;
     }
 
+    @Override
     public boolean isNoTileAtZoom(Map<String, List<String>> headers, int statusCode, byte[] content) {
         // default handler - when HTTP 404 is returned, then treat this situation as no tile at this zoom level
         return statusCode == 404;
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
index c5e8169..0f4887e 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/BingAerialTileSource.java
@@ -29,6 +29,7 @@ import javax.xml.xpath.XPathFactory;
 
 import org.openstreetmap.gui.jmapviewer.Coordinate;
 import org.openstreetmap.gui.jmapviewer.JMapViewer;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.w3c.dom.Document;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
@@ -37,7 +38,7 @@ import org.xml.sax.SAXException;
 
 public class BingAerialTileSource extends AbstractTMSTileSource {
 
-    private static String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU";
+    private static final String API_KEY = "Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU";
     private static volatile Future<List<Attribution>> attributions; // volatile is required for getAttribution(), see below.
     private static String imageUrlTemplate;
     private static Integer imageryZoomMax;
@@ -55,16 +56,20 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
         super(new TileSourceInfo("Bing", null, null));
     }
 
+    /**
+     * Constructs a new {@code BingAerialTileSource}.
+     * @param info imagery info
+     */
     public BingAerialTileSource(TileSourceInfo info) {
         super(info);
     }
 
-    protected class Attribution {
-        String attribution;
-        int minZoom;
-        int maxZoom;
-        Coordinate min;
-        Coordinate max;
+    protected static class Attribution {
+        private String attribution;
+        private int minZoom;
+        private int maxZoom;
+        private Coordinate min;
+        private Coordinate max;
     }
 
     @Override
@@ -98,11 +103,12 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
             XPath xpath = xPathFactory.newXPath();
             imageUrlTemplate = xpath.compile("//ImageryMetadata/ImageUrl/text()").evaluate(document);
             imageUrlTemplate = culturePattern.matcher(imageUrlTemplate).replaceAll(Locale.getDefault().toString());
-            imageryZoomMax = Integer.parseInt(xpath.compile("//ImageryMetadata/ZoomMax/text()").evaluate(document));
+            imageryZoomMax = Integer.valueOf(xpath.compile("//ImageryMetadata/ZoomMax/text()").evaluate(document));
 
-            NodeList subdomainTxt = (NodeList) xpath.compile("//ImageryMetadata/ImageUrlSubdomains/string/text()").evaluate(document, XPathConstants.NODESET);
+            NodeList subdomainTxt = (NodeList) xpath.compile("//ImageryMetadata/ImageUrlSubdomains/string/text()")
+                    .evaluate(document, XPathConstants.NODESET);
             subdomains = new String[subdomainTxt.getLength()];
-            for(int i = 0; i < subdomainTxt.getLength(); i++) {
+            for (int i = 0; i < subdomainTxt.getLength(); i++) {
                 subdomains[i] = subdomainTxt.item(i).getNodeValue();
             }
 
@@ -117,7 +123,8 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
             XPathExpression northLatXpath = xpath.compile("BoundingBox/NorthLatitude/text()");
             XPathExpression eastLonXpath = xpath.compile("BoundingBox/EastLongitude/text()");
 
-            NodeList imageryProviderNodes = (NodeList) xpath.compile("//ImageryMetadata/ImageryProvider").evaluate(document, XPathConstants.NODESET);
+            NodeList imageryProviderNodes = (NodeList) xpath.compile("//ImageryMetadata/ImageryProvider")
+                    .evaluate(document, XPathConstants.NODESET);
             List<Attribution> attributions = new ArrayList<>(imageryProviderNodes.getLength());
             for (int i = 0; i < imageryProviderNodes.getLength(); i++) {
                 Node providerNode = imageryProviderNodes.item(i);
@@ -125,7 +132,7 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
                 String attribution = attributionXpath.evaluate(providerNode);
 
                 NodeList coverageAreaNodes = (NodeList) coverageAreaXpath.evaluate(providerNode, XPathConstants.NODESET);
-                for(int j = 0; j < coverageAreaNodes.getLength(); j++) {
+                for (int j = 0; j < coverageAreaNodes.getLength(); j++) {
                     Node areaNode = coverageAreaNodes.item(j);
                     Attribution attr = new Attribution();
                     attr.attribution = attribution;
@@ -133,10 +140,10 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
                     attr.maxZoom = Integer.parseInt(zoomMaxXpath.evaluate(areaNode));
                     attr.minZoom = Integer.parseInt(zoomMinXpath.evaluate(areaNode));
 
-                    Double southLat = Double.parseDouble(southLatXpath.evaluate(areaNode));
-                    Double northLat = Double.parseDouble(northLatXpath.evaluate(areaNode));
-                    Double westLon = Double.parseDouble(westLonXpath.evaluate(areaNode));
-                    Double eastLon = Double.parseDouble(eastLonXpath.evaluate(areaNode));
+                    Double southLat = Double.valueOf(southLatXpath.evaluate(areaNode));
+                    Double northLat = Double.valueOf(northLatXpath.evaluate(areaNode));
+                    Double westLon = Double.valueOf(westLonXpath.evaluate(areaNode));
+                    Double eastLon = Double.valueOf(eastLonXpath.evaluate(areaNode));
                     attr.min = new Coordinate(southLat, westLon);
                     attr.max = new Coordinate(northLat, eastLon);
 
@@ -158,7 +165,7 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
 
     @Override
     public int getMaxZoom() {
-        if(imageryZoomMax != null)
+        if (imageryZoomMax != null)
             return imageryZoomMax;
         else
             return 22;
@@ -192,6 +199,9 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
                 // Some Linux distributions (like Debian) will remove Bing logo from sources, so get it at runtime
                 for (int i = 0; i < 5 && getAttribution() == null; i++) {
                     // Makes sure attribution is loaded
+                    if (JMapViewer.debug) {
+                        System.out.println("Bing attribution attempt " + (i+1));
+                    }
                 }
                 if (brandLogoUri != null && !brandLogoUri.isEmpty()) {
                     System.out.println("Reading Bing logo from "+brandLogoUri);
@@ -257,12 +267,13 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
         } catch (ExecutionException ex) {
             throw new RuntimeException(ex.getCause());
         } catch (InterruptedException ign) {
+            System.err.println("InterruptedException: " + ign.getMessage());
         }
         return null;
     }
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         try {
             final List<Attribution> data = getAttribution();
             if (data == null)
@@ -273,7 +284,7 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
                     if (topLeft.getLon() < attr.max.getLon() && botRight.getLon() > attr.min.getLon()
                             && topLeft.getLat() > attr.min.getLat() && botRight.getLat() < attr.max.getLat()) {
                         a.append(attr.attribution);
-                        a.append(" ");
+                        a.append(' ');
                     }
                 }
             }
@@ -284,7 +295,7 @@ public class BingAerialTileSource extends AbstractTMSTileSource {
         return "Error loading Bing attribution data";
     }
 
-    static String computeQuadTree(int zoom, int tilex, int tiley) {
+    private static String computeQuadTree(int zoom, int tilex, int tiley) {
         StringBuilder k = new StringBuilder();
         for (int i = zoom; i > 0; i--) {
             char digit = 48;
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java
index 719b2e1..0a81665 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOpenAerialTileSource.java
@@ -1,7 +1,7 @@
 // License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class MapQuestOpenAerialTileSource extends AbstractMapQuestTileSource {
 
@@ -12,7 +12,7 @@ public class MapQuestOpenAerialTileSource extends AbstractMapQuestTileSource {
     }
 
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft, Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft, ICoordinate botRight) {
         return "Portions Courtesy NASA/JPL-Caltech and U.S. Depart. of Agriculture, Farm Service Agency - "+MAPQUEST_ATTRIBUTION;
     }
 
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java
index 010f9de..18d01de 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/MapQuestOsmTileSource.java
@@ -1,7 +1,7 @@
 // License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
-import org.openstreetmap.gui.jmapviewer.Coordinate;
+import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 
 public class MapQuestOsmTileSource extends AbstractMapQuestTileSource {
 
@@ -12,8 +12,8 @@ public class MapQuestOsmTileSource extends AbstractMapQuestTileSource {
     }
     
     @Override
-    public String getAttributionText(int zoom, Coordinate topLeft,
-            Coordinate botRight) {
+    public String getAttributionText(int zoom, ICoordinate topLeft,
+            ICoordinate botRight) {
         return super.getAttributionText(zoom, topLeft, botRight)+" - "+MAPQUEST_ATTRIBUTION;
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
index ab83fe3..99adb0c 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/OsmTileSource.java
@@ -13,9 +13,9 @@ public class OsmTileSource {
 
         private static final String PATTERN = "https://%s.tile.openstreetmap.org";
 
-        private static final String[] SERVER = { "a", "b", "c" };
+        private static final String[] SERVER = {"a", "b", "c"};
 
-        private int SERVER_NUM = 0;
+        private int serverNum = 0;
 
         /**
          * Constructs a new {@code "Mapnik"} tile source.
@@ -26,16 +26,12 @@ public class OsmTileSource {
 
         @Override
         public String getBaseUrl() {
-            String url = String.format(this.baseUrl, new Object[] { SERVER[SERVER_NUM] });
-            SERVER_NUM = (SERVER_NUM + 1) % SERVER.length;
+            String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]});
+            serverNum = (serverNum + 1) % SERVER.length;
             return url;
         }
 
         @Override
-        public int getMaxZoom() {
-            return 19;
-        }
-
         public TileUpdate getTileUpdate() {
             return TileUpdate.IfNoneMatch;
         }
@@ -48,9 +44,9 @@ public class OsmTileSource {
 
         private static final String PATTERN = "http://%s.tile.opencyclemap.org/cycle";
 
-        private static final String[] SERVER = { "a", "b", "c" };
+        private static final String[] SERVER = {"a", "b", "c"};
 
-        private int SERVER_NUM = 0;
+        private int serverNum = 0;
 
         /**
          * Constructs a new {@code CycleMap} tile source.
@@ -61,8 +57,8 @@ public class OsmTileSource {
 
         @Override
         public String getBaseUrl() {
-            String url = String.format(this.baseUrl, new Object[] { SERVER[SERVER_NUM] });
-            SERVER_NUM = (SERVER_NUM + 1) % SERVER.length;
+            String url = String.format(this.baseUrl, new Object[] {SERVER[serverNum]});
+            serverNum = (serverNum + 1) % SERVER.length;
             return url;
         }
 
@@ -71,6 +67,7 @@ public class OsmTileSource {
             return 18;
         }
 
+        @Override
         public TileUpdate getTileUpdate() {
             return TileUpdate.LastModified;
         }
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
index 9d0d502..0dce239 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/ScanexTileSource.java
@@ -1,27 +1,34 @@
-// License: BSD or GPL. For details, see Readme.txt file.
+// License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
 import java.util.Random;
 
 import org.openstreetmap.gui.jmapviewer.OsmMercator;
 
-/*
+/**
  * This tilesource uses different to OsmMercator projection.
  *
  * Earth is assumed an ellipsoid in this projection, unlike
- * sphere in OsmMercator, so latitude calculation differs
- * a lot.
+ * sphere in OsmMercator, so latitude calculation differs a lot.
  *
  * The longitude calculation is the same as in OsmMercator,
  * we inherit it from AbstractTMSTileSource.
  *
  * TODO: correct getDistance() method.
  */
-
 public class ScanexTileSource extends TMSTileSource {
     private static final String DEFAULT_URL = "http://maps.kosmosnimki.ru";
     private static final int DEFAULT_MAXZOOM = 14;
-    private static String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7";
+    private static final String API_KEY = "4018C5A9AECAD8868ED5DEB2E41D09F7";
+
+    // Latitude to Y and back calculations.
+
+    /** radius of Earth at equator, m */
+    private static double RADIUS_E = 6378137;
+    /** equator length, m */
+    private static double EQUATOR = 40075016.68557849;
+    /** eccentricity of Earth's ellipsoid */
+    private static double E = 0.0818191908426;
 
     private enum ScanexLayer {
         IRS("irs", "/TileSender.ashx?ModeKey=tile&MapName=F7B8CF651682420FA1749D894C8AD0F6&LayerName=BAC78D764F0443BD9AF93E7A998C9F5B"),
@@ -34,27 +41,34 @@ public class ScanexTileSource extends TMSTileSource {
             this.name = name;
             this.uri = uri;
         }
+
         public String getName() {
             return name;
         }
+
         public String getUri() {
             return uri;
         }
     }
 
-    /* IRS by default */
-    private ScanexLayer Layer = ScanexLayer.IRS;
+    /** IRS by default */
+    private ScanexLayer layer = ScanexLayer.IRS;
+
+    /** cached latitude used in {@link #tileYToLat(double, int)} */
+    private double cachedLat = 0;
 
+    /**
+     * Constructs a new {@code ScanexTileSource}.
+     * @param info tile source info
+     */
     public ScanexTileSource(TileSourceInfo info) {
         super(info);
         String url = info.getUrl();
 
-        for (ScanexLayer layer : ScanexLayer.values()) {
-            if (url.equalsIgnoreCase(layer.getName())) {
-                this.Layer = layer;
-                /*
-                 * Override baseUrl and maxZoom in base class.
-                 */
+        for (ScanexLayer slayer : ScanexLayer.values()) {
+            if (url.equalsIgnoreCase(slayer.getName())) {
+                this.layer = slayer;
+                // Override baseUrl and maxZoom in base class.
                 this.baseUrl = DEFAULT_URL;
                 if (maxZoom == 0)
                     this.maxZoom = DEFAULT_MAXZOOM;
@@ -65,40 +79,27 @@ public class ScanexTileSource extends TMSTileSource {
 
     @Override
     public String getExtension() {
-        return("jpeg");
+        return "jpeg";
     }
 
     @Override
     public String getTilePath(int zoom, int tilex, int tiley) {
-        int tmp = (int)Math.pow(2.0, zoom - 1);
+        int tmp = (int) Math.pow(2.0, zoom - 1);
 
         tilex = tilex - tmp;
         tiley = tmp - tiley - 1;
 
-        return this.Layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom;
+        return this.layer.getUri() + "&apikey=" + API_KEY + "&x=" + tilex + "&y=" + tiley + "&z=" + zoom;
     }
 
     @Override
-    public TileUpdate getTileUpdate() {
-        return TileUpdate.IfNoneMatch;
-    }
-
-
-    /*
-     * Latitude to Y and back calculations.
-     */
-    private static double RADIUS_E = 6378137;   /* radius of Earth at equator, m */
-    private static double EQUATOR = 40075016.68557849; /* equator length, m */
-    private static double E = 0.0818191908426;  /* eccentricity of Earth's ellipsoid */
-
-    @Override
-    public int LatToY(double lat, int zoom) {
-        return (int )(latToTileY(lat, zoom) * tileSize);
+    public int latToY(double lat, int zoom) {
+        return (int) (latToTileY(lat, zoom) * tileSize);
     }
 
     @Override
     public double YToLat(int y, int zoom) {
-        return tileYToLat((double )y / tileSize, zoom);
+        return tileYToLat((double) y / tileSize, zoom);
     }
 
     @Override
@@ -111,50 +112,46 @@ public class ScanexTileSource extends TMSTileSource {
 
     @Override
     public double tileYToLat(int y, int zoom) {
-        return tileYToLat((double )y, zoom);
+        return tileYToLat((double) y, zoom);
     }
 
     /*
      * To solve inverse formula latitude = f(y) we use
      * Newton's method. We cache previous calculated latitude,
      * because new one is usually close to the old one. In case
-     * if solution gets out of bounds, we reset to a new random
-     * value.
+     * if solution gets out of bounds, we reset to a new random value.
      */
-    private double cached_lat = 0;
     private double tileYToLat(double y, int zoom) {
-        double lat0, lat;
-
-        lat = cached_lat;
+        double lat0;
+        double lat = cachedLat;
         do {
             lat0 = lat;
-            lat = lat - Math.toDegrees(NextTerm(Math.toRadians(lat), y, zoom));
+            lat = lat - Math.toDegrees(nextTerm(Math.toRadians(lat), y, zoom));
             if (lat > OsmMercator.MAX_LAT || lat < OsmMercator.MIN_LAT) {
                 Random r = new Random();
                 lat = OsmMercator.MIN_LAT +
-                  r.nextInt((int )(OsmMercator.MAX_LAT - OsmMercator.MIN_LAT));
+                  r.nextInt((int) (OsmMercator.MAX_LAT - OsmMercator.MIN_LAT));
             }
-        } while ((Math.abs(lat0 - lat) > 0.000001));
+        } while (Math.abs(lat0 - lat) > 0.000001);
 
-        cached_lat = lat;
+        cachedLat = lat;
 
-        return (lat);
+        return lat;
     }
 
     /* Next term in Newton's polynomial */
-    private double NextTerm(double lat, double y, int zoom) {
-        double sinl=Math.sin(lat);
-        double cosl=Math.cos(lat);
-        double ec, f, df;
+    private static double nextTerm(double lat, double y, int zoom) {
+        double sinl = Math.sin(lat);
+        double cosl = Math.cos(lat);
 
-        zoom = (int )Math.pow(2.0, zoom - 1);
-        ec = Math.exp((1 - y/zoom)*Math.PI);
+        zoom = (int) Math.pow(2.0, zoom - 1);
+        double ec = Math.exp((1 - y/zoom)*Math.PI);
 
-        f = (Math.tan(Math.PI/4+lat/2) -
-            ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E));
-        df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) *
-            (Math.sqrt (1 - E * E * sinl * sinl)));
+        double f = Math.tan(Math.PI/4+lat/2) -
+            ec * Math.pow(Math.tan(Math.PI/4 + Math.asin(E * sinl)/2), E);
+        double df = 1/(1 - sinl) - ec * E * cosl/((1 - E * sinl) *
+            (Math.sqrt(1 - E * E * sinl * sinl)));
 
-        return (f/df);
+        return f/df;
     }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
index cf163bf..6795a68 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/TemplatedTMSTileSource.java
@@ -7,26 +7,52 @@ import java.util.Random;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-public class TemplatedTMSTileSource extends TMSTileSource {
+import org.openstreetmap.gui.jmapviewer.interfaces.TemplatedTileSource;
+
+/**
+ * Handles templated TMS Tile Source. Templated means, that some patterns within
+ * URL gets substituted.
+ *
+ * Supported parameters
+ * {zoom} - substituted with zoom level
+ * {z} - as above
+ * {NUMBER-zoom} - substituted with result of equation "NUMBER - zoom",
+ *                  eg. {20-zoom} for zoom level 15 will result in 5 in this place
+ * {zoom+number} - substituted with result of equation "zoom + number",
+ *                 eg. {zoom+5} for zoom level 15 will result in 20.
+ * {x} - substituted with X tile number
+ * {y} - substituted with Y tile number
+ * {!y} - substituted with Yahoo Y tile number
+ * {-y} - substituted with reversed Y tile number
+ * {switch:VAL_A,VAL_B,VAL_C,...} - substituted with one of VAL_A, VAL_B, VAL_C. Usually
+ *                                  used to specify many tile servers
+ * {header:(HEADER_NAME,HEADER_VALUE)} - sets the headers to be sent to tile server
+ */
+
+public class TemplatedTMSTileSource extends TMSTileSource implements TemplatedTileSource {
 
     private Random rand = null;
     private String[] randomParts = null;
-    private Map<String, String> headers = new HashMap<>();
+    private final Map<String, String> headers = new HashMap<>();
 
-    public static final String COOKIE_HEADER   = "Cookie";
-    public static final String PATTERN_ZOOM    = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}";
-    public static final String PATTERN_X       = "\\{x\\}";
-    public static final String PATTERN_Y       = "\\{y\\}";
-    public static final String PATTERN_Y_YAHOO = "\\{!y\\}";
-    public static final String PATTERN_NEG_Y   = "\\{-y\\}";
-    public static final String PATTERN_SWITCH  = "\\{switch:([^}]+)\\}";
-    public static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
+    private static final String COOKIE_HEADER   = "Cookie";
+    private static final String PATTERN_ZOOM    = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}";
+    private static final String PATTERN_X       = "\\{x\\}";
+    private static final String PATTERN_Y       = "\\{y\\}";
+    private static final String PATTERN_Y_YAHOO = "\\{!y\\}";
+    private static final String PATTERN_NEG_Y   = "\\{-y\\}";
+    private static final String PATTERN_SWITCH  = "\\{switch:([^}]+)\\}";
+    private static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
 
-    public static final String[] ALL_PATTERNS = {
+    private static final String[] ALL_PATTERNS = {
         PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y,
         PATTERN_SWITCH
     };
 
+    /**
+     * Creates Templated TMS Tile Source based on ImageryInfo
+     * @param info imagery info
+     */
     public TemplatedTMSTileSource(TileSourceInfo info) {
         super(info);
         if (info.getCookies() != null) {
@@ -46,13 +72,14 @@ public class TemplatedTMSTileSource extends TMSTileSource {
         StringBuffer output = new StringBuffer();
         Matcher matcher = pattern.matcher(baseUrl);
         while (matcher.find()) {
-            headers.put(matcher.group(1),matcher.group(2));
+            headers.put(matcher.group(1), matcher.group(2));
             matcher.appendReplacement(output, "");
         }
         matcher.appendTail(output);
         baseUrl = output.toString();
     }
 
+    @Override
     public Map<String, String> getHeaders() {
         return headers;
     }
@@ -62,25 +89,47 @@ public class TemplatedTMSTileSource extends TMSTileSource {
         int finalZoom = zoom;
         Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl);
         if (m.matches()) {
-            if(m.group(1) != null) {
-                finalZoom = Integer.valueOf(m.group(1))-zoom;
+            if (m.group(1) != null) {
+                finalZoom = Integer.parseInt(m.group(1))-zoom;
             }
-            if(m.group(2) != null) {
+            if (m.group(2) != null) {
                 String ofs = m.group(2);
-                if(ofs.startsWith("+"))
+                if (ofs.startsWith("+"))
                     ofs = ofs.substring(1);
-                finalZoom += Integer.valueOf(ofs);
+                finalZoom += Integer.parseInt(ofs);
             }
         }
         String r = this.baseUrl
             .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom))
             .replaceAll(PATTERN_X, Integer.toString(tilex))
             .replaceAll(PATTERN_Y, Integer.toString(tiley))
-            .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int)Math.pow(2, zoom-1)-1-tiley))
-            .replaceAll(PATTERN_NEG_Y, Integer.toString((int)Math.pow(2, zoom)-1-tiley));
+            .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int) Math.pow(2, zoom-1)-1-tiley))
+            .replaceAll(PATTERN_NEG_Y, Integer.toString((int) Math.pow(2, zoom)-1-tiley));
         if (rand != null) {
             r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]);
         }
         return r;
     }
+
+    /**
+     * Checks if url is acceptable by this Tile Source
+     * @param url URL to check
+     */
+    public static void checkUrl(String url) {
+        assert url != null && !"".equals(url) : "URL cannot be null or empty";
+        Matcher m = Pattern.compile("\\{[^}]*\\}").matcher(url);
+        while (m.find()) {
+            boolean isSupportedPattern = false;
+            for (String pattern : ALL_PATTERNS) {
+                if (m.group().matches(pattern)) {
+                    isSupportedPattern = true;
+                    break;
+                }
+            }
+            if (!isSupportedPattern) {
+                throw new IllegalArgumentException(
+                        m.group() + " is not a valid TMS argument. Please check this server URL:\n" + url);
+            }
+        }
+    }
 }
diff --git a/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java b/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
index 49591ec..56d70a5 100644
--- a/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
+++ b/src/org/openstreetmap/gui/jmapviewer/tilesources/TileSourceInfo.java
@@ -1,4 +1,4 @@
-// License: GPL. For details, see LICENSE file.
+// License: GPL. For details, see Readme.txt file.
 package org.openstreetmap.gui.jmapviewer.tilesources;
 
 import java.util.Map;
@@ -13,8 +13,9 @@ import org.openstreetmap.gui.jmapviewer.OsmMercator;
 public class TileSourceInfo {
     /** id for this imagery entry, optional at the moment */
     protected String id;
+
     /** URL of the imagery service */
-    protected  String url = null;
+    protected String url;
 
     /** name of the imagery layer */
     protected String name;
@@ -29,23 +30,23 @@ public class TileSourceInfo {
     protected int maxZoom;
 
     /** cookies that needs to be sent to tile source */
-    protected String cookies;
+    protected String cookies = "";
 
     /** tile size of the displayed tiles */
-    private int tileSize = OsmMercator.DEFAUL_TILE_SIZE;
+    private int tileSize = OsmMercator.DEFAUL_TILE_SIZE; // FIXME: set to -1 for next release
 
-    /** mapping <header key, metadata key> */
+    /** mapping <header key, metadata key> */
     protected Map<String, String> metadataHeaders;
 
     /**
      * Create a TileSourceInfo class
      *
-     * @param name
-     * @param base_url
-     * @param id
+     * @param name name
+     * @param base_url base URL
+     * @param id unique id
      */
     public TileSourceInfo(String name, String base_url, String id) {
-        this(name);
+        this.name = name;
         this.url = base_url;
         this.id = id;
     }
@@ -53,23 +54,24 @@ public class TileSourceInfo {
     /**
      * Create a TileSourceInfo class
      *
-     * @param name
+     * @param name name
      */
     public TileSourceInfo(String name) {
-        this.name = name;
+        this(name, null, null);
     }
 
     /**
      * Creates empty TileSourceInfo class
      */
     public TileSourceInfo() {
+        this(null, null, null);
     }
 
     /**
      * Request name of the tile source
      * @return name of the tile source
      */
-    public String getName() {
+    public final String getName() {
         return name;
     }
 
@@ -77,11 +79,20 @@ public class TileSourceInfo {
      * Request URL of the tile source
      * @return url of the tile source
      */
-    public String getUrl() {
+    public final String getUrl() {
         return url;
     }
 
     /**
+     * Request ID of the tile source. Id can be null. This gets the configured id as is.
+     * Due to a user error, this may not be unique.
+     * @return id of the tile source
+     */
+    public final String getId() {
+        return id;
+    }
+
+    /**
      * Request header information for empty tiles for servers delivering such tile types
      * @return map of headers, that when set, means that this is "no tile at this zoom level" situation
      */
@@ -115,29 +126,53 @@ public class TileSourceInfo {
 
     /**
      * Request tile size of this tile source
-     * @return tile size provided by this tile source
+     * @return tile size provided by this tile source, or -1 when default value should be used
      */
     public int getTileSize() {
         return tileSize;
     }
 
     /**
+     * Request metadata headers
+     * @return mapping <HTTP header name, Metadata key name> for copying HTTP headers to Tile metadata
+     * @since 31125
+     */
+    public Map<String, String> getMetadataHeaders() {
+        return metadataHeaders;
+    }
+
+    /**
      * Sets the tile size provided by this tile source
-     * @param tileSize
+     * @param tileSize tile size in pixels
      */
-    public void setTileSize(int tileSize) {
-        if (tileSize <= 0) {
+    public final void setTileSize(int tileSize) {
+        if (tileSize == 0 || tileSize < -1) {
             throw new AssertionError("Invalid tile size: " + tileSize);
         }
         this.tileSize = tileSize;
     }
 
     /**
-     *
-     * @return mapping <HTTP header name, Metadata key name> for copying HTTP headers to Tile metadata
-     * @since 31125
+     * Sets the tile URL.
+     * @param url tile URL
      */
-    public Map<String, String> getMetadataHeaders() {
-        return metadataHeaders;
+    public final void setUrl(String url) {
+        this.url = url;
+    }
+
+    /**
+     * Sets the tile name.
+     * @param name tile name
+     */
+    public final void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Sets the tile id.
+     * @param id tile id
+     */
+    public final void setId(String id) {
+        this.id = id;
     }
 }

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/jmapviewer.git



More information about the Pkg-grass-devel mailing list