Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Demo.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Demo.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/Demo.java	(revision 11103)
@@ -109,5 +109,5 @@
 		map.addMapMarker(new MapMarkerDot(49.71, 8.64));
 		map.addMapMarker(new MapMarkerDot(48.71, -1));
-		map.addMapMarker(new MapMarkerDot(49.807, 8.644));
+		map.addMapMarker(new MapMarkerDot(49.8588, 8.643));
 
 		// map.setDisplayPositionByLatLon(49.807, 8.6, 11);
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java	(revision 11103)
@@ -45,8 +45,8 @@
 	 * 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) };
-
-	public static final int MAX_ZOOM = 18;
+	protected 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;
 
@@ -107,6 +107,6 @@
 		setPreferredSize(new Dimension(400, 400));
 		try {
-			loadingImage =
-					ImageIO.read(JMapViewer.class.getResourceAsStream("images/hourglass.png"));
+			loadingImage = ImageIO.read(JMapViewer.class
+					.getResourceAsStream("images/hourglass.png"));
 		} catch (Exception e1) {
 			loadingImage = null;
@@ -128,5 +128,6 @@
 		int size = 18;
 		try {
-			ImageIcon icon = new ImageIcon(getClass().getResource("images/plus.png"));
+			ImageIcon icon = new ImageIcon(getClass().getResource(
+					"images/plus.png"));
 			zoomInButton = new JButton(icon);
 		} catch (Exception e) {
@@ -144,5 +145,6 @@
 		add(zoomInButton);
 		try {
-			ImageIcon icon = new ImageIcon(getClass().getResource("images/minus.png"));
+			ImageIcon icon = new ImageIcon(getClass().getResource(
+					"images/minus.png"));
 			zoomOutButton = new JButton(icon);
 		} catch (Exception e) {
@@ -173,5 +175,6 @@
 	 */
 	public void setDisplayPositionByLatLon(double lat, double lon, int zoom) {
-		setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), lat, lon, zoom);
+		setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2),
+				lat, lon, zoom);
 	}
 
@@ -192,5 +195,6 @@
 	 *            {@link TileSource#getMaxZoom()}
 	 */
-	public void setDisplayPositionByLatLon(Point mapPoint, double lat, double lon, int zoom) {
+	public void setDisplayPositionByLatLon(Point mapPoint, double lat,
+			double lon, int zoom) {
 		int x = OsmMercator.LonToX(lon, zoom);
 		int y = OsmMercator.LatToY(lat, zoom);
@@ -199,5 +203,6 @@
 
 	public void setDisplayPosition(int x, int y, int zoom) {
-		setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom);
+		setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y,
+				zoom);
 	}
 
@@ -236,7 +241,8 @@
 		int x_max = Integer.MIN_VALUE;
 		int y_max = Integer.MIN_VALUE;
+		int mapZoomMax = tileSource.getMaxZoom();
 		for (MapMarker marker : mapMarkerList) {
-			int x = OsmMercator.LonToX(marker.getLon(), MAX_ZOOM);
-			int y = OsmMercator.LatToY(marker.getLat(), MAX_ZOOM);
+			int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax);
+			int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax);
 			x_max = Math.max(x_max, x);
 			y_max = Math.max(y_max, y);
@@ -249,5 +255,5 @@
 		// System.out.println(y_min + " < y < " + y_max);
 		// System.out.println("tiles: " + width + " " + height);
-		int newZoom = MAX_ZOOM;
+		int newZoom = mapZoomMax;
 		int x = x_max - x_min;
 		int y = y_max - y_min;
@@ -260,5 +266,5 @@
 		x = x_min + (x_max - x_min) / 2;
 		y = y_min + (y_max - y_min) / 2;
-		int z = 1 << (MAX_ZOOM - newZoom);
+		int z = 1 << (mapZoomMax - newZoom);
 		x /= z;
 		y /= z;
@@ -346,5 +352,6 @@
 					x++;
 				for (int j = 0; j < x; j++) {
-					if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) {
+					if (x_min <= posx && posx <= x_max && y_min <= posy
+							&& posy <= y_max) {
 						// tile is visible
 						Tile tile = getTile(tilex, tiley, zoom);
@@ -463,5 +470,6 @@
 		}
 		if (!tile.isLoaded()) {
-			jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource, tilex, tiley, zoom));
+			jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource,
+					tilex, tiley, zoom));
 		}
 		return tile;
@@ -544,4 +552,6 @@
 
 	public void setTileSource(TileSource tileSource) {
+		if (tileSource.getMaxZoom() > MAX_ZOOM)
+			throw new RuntimeException("Zoom level too high");
 		this.tileSource = tileSource;
 		zoomSlider.setMaximum(tileSource.getMaxZoom());
@@ -552,3 +562,7 @@
 	}
 
+	public void tileLoadingFinished(Tile tile) {
+		repaint();
+	}
+
 }
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmFileCacheTileLoader.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmFileCacheTileLoader.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmFileCacheTileLoader.java	(revision 11103)
@@ -30,5 +30,4 @@
 public class OsmFileCacheTileLoader extends OsmTileLoader {
 
-	private static final String TILE_FILE_EXT = ".png";
 	private static final String ETAG_FILE_EXT = ".etag";
 
@@ -59,6 +58,6 @@
 	}
 
-	public Runnable createTileLoaderJob(final TileSource source, final int tilex, final int tiley,
-			final int zoom) {
+	public Runnable createTileLoaderJob(final TileSource source,
+			final int tilex, final int tiley, final int zoom) {
 		return new FileLoadJob(source, tilex, tiley, zoom);
 	}
@@ -121,9 +120,10 @@
 					case LastModified:
 						if (!isOsmTileNewer(fileAge)) {
-							System.out
-									.println("LastModified: Local version is up to date: " + tile);
+							// System.out.println(
+							// "LastModified: Local version is up to date: " +
+							// tile);
 							tile.setLoaded(true);
-							tileFile.setLastModified(System.currentTimeMillis() - maxCacheFileAge
-									+ recheckAfter);
+							tileFile.setLastModified(System.currentTimeMillis()
+									- maxCacheFileAge + recheckAfter);
 							return;
 						}
@@ -138,10 +138,12 @@
 							switch (source.getTileUpdate()) {
 							case IfNoneMatch:
-								urlConn.addRequestProperty("If-None-Match", fileETag);
+								urlConn.addRequestProperty("If-None-Match",
+										fileETag);
 								break;
 							case ETag:
 								if (hasOsmTileETag(fileETag)) {
 									tile.setLoaded(true);
-									tileFile.setLastModified(System.currentTimeMillis()
+									tileFile.setLastModified(System
+											.currentTimeMillis()
 											- maxCacheFileAge + recheckAfter);
 									return;
@@ -159,6 +161,6 @@
 					System.out.println("Local version is up to date: " + tile);
 					tile.setLoaded(true);
-					tileFile.setLastModified(System.currentTimeMillis() - maxCacheFileAge
-							+ recheckAfter);
+					tileFile.setLastModified(System.currentTimeMillis()
+							- maxCacheFileAge + recheckAfter);
 					return;
 				}
@@ -168,5 +170,5 @@
 					tile.loadImage(new ByteArrayInputStream(buffer));
 					tile.setLoaded(true);
-					listener.repaint();
+					listener.tileLoadingFinished(tile);
 					saveTileToFile(buffer);
 				} else {
@@ -175,6 +177,6 @@
 			} catch (Exception e) {
 				if (input == null /* || !input.isStopped() */)
-					System.err.println("failed loading " + zoom + "/" + tilex + "/" + tiley + " "
-							+ e.getMessage());
+					System.err.println("failed loading " + zoom + "/" + tilex
+							+ "/" + tiley + " " + e.getMessage());
 			} finally {
 				tile.loading = false;
@@ -196,9 +198,9 @@
 				if (!oldTile) {
 					tile.setLoaded(true);
-					listener.repaint();
+					listener.tileLoadingFinished(tile);
 					fileTilePainted = true;
 					return true;
 				}
-				listener.repaint();
+				listener.tileLoadingFinished(tile);
 				fileTilePainted = true;
 			} catch (Exception e) {
@@ -216,7 +218,9 @@
 		}
 
-		protected byte[] loadTileInBuffer(URLConnection urlConn) throws IOException {
+		protected byte[] loadTileInBuffer(URLConnection urlConn)
+				throws IOException {
 			input = urlConn.getInputStream();
-			ByteArrayOutputStream bout = new ByteArrayOutputStream(input.available());
+			ByteArrayOutputStream bout = new ByteArrayOutputStream(input
+					.available());
 			byte[] buffer = new byte[2048];
 			boolean finished = false;
@@ -252,5 +256,6 @@
 			URL url;
 			url = new URL(tile.getUrl());
-			HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
+			HttpURLConnection urlConn = (HttpURLConnection) url
+					.openConnection();
 			urlConn.setRequestMethod("HEAD");
 			urlConn.setReadTimeout(30000); // 30 seconds read timeout
@@ -267,5 +272,6 @@
 			URL url;
 			url = new URL(tile.getUrl());
-			HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
+			HttpURLConnection urlConn = (HttpURLConnection) url
+					.openConnection();
 			urlConn.setRequestMethod("HEAD");
 			urlConn.setReadTimeout(30000); // 30 seconds read timeout
@@ -280,18 +286,20 @@
 
 		protected File getTileFile() throws IOException {
-			return new File(tileCacheDir + "/" + tile.getZoom() + "_" + tile.getXtile() + "_"
-					+ tile.getYtile() + TILE_FILE_EXT);
+			return new File(tileCacheDir + "/" + tile.getZoom() + "_"
+					+ tile.getXtile() + "_" + tile.getYtile() + "."
+					+ source.getTileType());
 		}
 
 		protected void saveTileToFile(byte[] rawData) {
 			try {
-				FileOutputStream f =
-						new FileOutputStream(tileCacheDir + "/" + tile.getZoom() + "_"
-								+ tile.getXtile() + "_" + tile.getYtile() + TILE_FILE_EXT);
+				FileOutputStream f = new FileOutputStream(tileCacheDir + "/"
+						+ tile.getZoom() + "_" + tile.getXtile() + "_"
+						+ tile.getYtile() + "." + source.getTileType());
 				f.write(rawData);
 				f.close();
 				// System.out.println("Saved tile to file: " + tile);
 			} catch (Exception e) {
-				System.err.println("Failed to save tile content: " + e.getLocalizedMessage());
+				System.err.println("Failed to save tile content: "
+						+ e.getLocalizedMessage());
 			}
 		}
@@ -299,11 +307,12 @@
 		protected void saveETagToFile(String eTag) {
 			try {
-				FileOutputStream f =
-						new FileOutputStream(tileCacheDir + "/" + tile.getZoom() + "_"
-								+ tile.getXtile() + "_" + tile.getYtile() + ETAG_FILE_EXT);
+				FileOutputStream f = new FileOutputStream(tileCacheDir + "/"
+						+ tile.getZoom() + "_" + tile.getXtile() + "_"
+						+ tile.getYtile() + ETAG_FILE_EXT);
 				f.write(eTag.getBytes(ETAG_CHARSET.name()));
 				f.close();
 			} catch (Exception e) {
-				System.err.println("Failed to save ETag: " + e.getLocalizedMessage());
+				System.err.println("Failed to save ETag: "
+						+ e.getLocalizedMessage());
 			}
 		}
@@ -311,7 +320,7 @@
 		protected String loadETagfromFile() {
 			try {
-				FileInputStream f =
-						new FileInputStream(tileCacheDir + "/" + tile.getZoom() + "_"
-								+ tile.getXtile() + "_" + tile.getYtile() + ETAG_FILE_EXT);
+				FileInputStream f = new FileInputStream(tileCacheDir + "/"
+						+ tile.getZoom() + "_" + tile.getXtile() + "_"
+						+ tile.getYtile() + ETAG_FILE_EXT);
 				byte[] buf = new byte[f.available()];
 				f.read(buf);
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileLoader.java	(revision 11103)
@@ -46,5 +46,5 @@
 					tile.loadImage(input);
 					tile.setLoaded(true);
-					listener.repaint();
+					listener.tileLoadingFinished(tile);
 					input.close();
 					input = null;
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileSource.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/OsmTileSource.java	(revision 11103)
@@ -23,10 +23,17 @@
 			return getName();
 		}
+
+		public String getTileType() {
+			return "png";
+		}
+		
 	}
 
 	public static class Mapnik extends AbstractOsmTileSource {
 
+		public static String NAME = "Mapnik";
+		
 		public String getName() {
-			return "Mapnik";
+			return NAME;
 		}
 
@@ -43,7 +50,9 @@
 
 	public static class CycleMap extends AbstractOsmTileSource {
+		
+		public static String NAME = "OSM Cycle Map";
 
 		public String getName() {
-			return "OSM Cycle Map";
+			return NAME;
 		}
 
@@ -61,4 +70,6 @@
 	public static class TilesAtHome extends AbstractOsmTileSource {
 
+		public static String NAME = "TilesAtHome";
+
 		public int getMaxZoom() {
 			return 17;
@@ -66,5 +77,5 @@
 
 		public String getName() {
-			return "TilesAtHome";
+			return NAME;
 		}
 
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileLoaderListener.java	(revision 11103)
@@ -1,9 +1,17 @@
 package org.openstreetmap.gui.jmapviewer.interfaces;
+
+import org.openstreetmap.gui.jmapviewer.Tile;
 
 //License: GPL. Copyright 2008 by Jan Peter Stotz
 
 public interface TileLoaderListener {
-	
-	public void repaint();
+
+	/**
+	 * Will be called if a new {@link Tile} has been loaded successfully. 
+	 * Loaded can mean downloaded or loaded from file cache. 
+	 * 
+	 * @param tile
+	 */
+	public void tileLoadingFinished(Tile tile);
 
 	public TileCache getTileCache();
Index: applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java
===================================================================
--- applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 10722)
+++ applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/interfaces/TileSource.java	(revision 11103)
@@ -61,4 +61,6 @@
 
 	/**
+	 * Constructs the tile url.
+	 * 
 	 * @param zoom
 	 * @param tilex
@@ -67,3 +69,11 @@
 	 */
 	public String getTileUrl(int zoom, int tilex, int tiley);
+
+	/**
+	 * Specifies the tile image type. For tiles rendered by Mapnik or
+	 * Osmarenderer this is usually <code>"png"</code>.
+	 * 
+	 * @return file extension of the tile image type
+	 */
+	public String getTileType();
 }
