Index: /trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/data/cache/JCSCachedTileLoaderJob.java	(revision 8602)
@@ -14,7 +14,5 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.Executors;
 import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -79,17 +77,8 @@
             // make queue of LIFO type - so recently requested tiles will be loaded first (assuming that these are which user is waiting to see)
             new LinkedBlockingDeque<Runnable>(),
-            getNamedThreadFactory("JCS downloader")
+            Utils.getNamedThreadFactory("JCS downloader")
             );
 
-    public static ThreadFactory getNamedThreadFactory(final String name) {
-        return new ThreadFactory() {
-            @Override
-            public Thread newThread(Runnable r) {
-                Thread t = Executors.defaultThreadFactory().newThread(r);
-                t.setName(name);
-                return t;
-            }
-        };
-    }
+
 
     private static ConcurrentMap<String, Set<ICachedLoaderListener>> inProgress = new ConcurrentHashMap<>();
@@ -312,5 +301,5 @@
             }
 
-            URLConnection urlConn = getURLConnection();
+            HttpURLConnection urlConn = getURLConnection();
 
             if (isObjectLoadable()  &&
@@ -321,35 +310,35 @@
                 urlConn.addRequestProperty("If-None-Match", attributes.getEtag());
             }
-            if (responseCode(urlConn) == 304) {
+            if (urlConn.getResponseCode() == 304) {
                 // If isModifiedSince or If-None-Match has been set
                 // and the server answers with a HTTP 304 = "Not Modified"
                 log.log(Level.FINE, "JCS - IfModifiedSince/Etag test: local version is up to date: {0}", getUrl());
                 return true;
-            } else if (isObjectLoadable()) {
-                // we have an object in cache, but we haven't received 304 resposne code
-                // check if we should use HEAD request to verify
-                if ((attributes.getEtag() != null && attributes.getEtag().equals(urlConn.getRequestProperty("ETag"))) ||
-                        attributes.getLastModification() == urlConn.getLastModified()) {
-                    // we sent ETag or If-Modified-Since, but didn't get 304 response code
-                    // for further requests - use HEAD
-                    String serverKey = getServerKey();
-                    log.log(Level.INFO, "JCS - Host: {0} found not to return 304 codes for If-Modifed-Since or If-None-Match headers",
-                            serverKey);
-                    useHead.put(serverKey, Boolean.TRUE);
-                }
-            }
+            } else if (isObjectLoadable() // we have an object in cache, but we haven't received 304 resposne code
+                    && (
+                            (attributes.getEtag() != null && attributes.getEtag().equals(urlConn.getRequestProperty("ETag"))) ||
+                            attributes.getLastModification() == urlConn.getLastModified())
+                    ) {
+                // we sent ETag or If-Modified-Since, but didn't get 304 response code
+                // for further requests - use HEAD
+                String serverKey = getServerKey();
+                log.log(Level.INFO, "JCS - Host: {0} found not to return 304 codes for If-Modifed-Since or If-None-Match headers",
+                        serverKey);
+                useHead.put(serverKey, Boolean.TRUE);
+            }
+
 
             attributes = parseHeaders(urlConn);
 
             for (int i = 0; i < 5; ++i) {
-                if (responseCode(urlConn) == 503) {
+                if (urlConn.getResponseCode() == 503) {
                     Thread.sleep(5000+(new Random()).nextInt(5000));
                     continue;
                 }
 
-                attributes.setResponseCode(responseCode(urlConn));
+                attributes.setResponseCode(urlConn.getResponseCode());
                 byte[] raw = Utils.readBytesFromStream(urlConn.getInputStream());
 
-                if (isResponseLoadable(urlConn.getHeaderFields(), responseCode(urlConn), raw)) {
+                if (isResponseLoadable(urlConn.getHeaderFields(), urlConn.getResponseCode(), raw)) {
                     // we need to check cacheEmpty, so for cases, when data is returned, but we want to store
                     // as empty (eg. empty tile images) to save some space
@@ -446,6 +435,6 @@
     }
 
-    private URLConnection getURLConnection() throws IOException {
-        URLConnection urlConn = getUrl().openConnection();
+    private HttpURLConnection getURLConnection() throws IOException {
+        HttpURLConnection urlConn = (HttpURLConnection) getUrl().openConnection();
         urlConn.setRequestProperty("Accept", "text/html, image/png, image/jpeg, image/gif, */*");
         urlConn.setReadTimeout(readTimeout); // 30 seconds read timeout
@@ -461,13 +450,9 @@
 
     private boolean isCacheValidUsingHead() throws IOException {
-        URLConnection urlConn = getUrl().openConnection();
-        if (urlConn instanceof HttpURLConnection) {
-            ((HttpURLConnection) urlConn).setRequestMethod("HEAD");
-            long lastModified = urlConn.getLastModified();
-            return (attributes.getEtag() != null && attributes.getEtag().equals(urlConn.getRequestProperty("ETag"))) ||
-                    (lastModified != 0 && lastModified <= attributes.getLastModification());
-        }
-        // for other URL connections, do not use HEAD requests for cache validation
-        return false;
+        HttpURLConnection urlConn = getURLConnection();
+        urlConn.setRequestMethod("HEAD");
+        long lastModified = urlConn.getLastModified();
+        return (attributes.getEtag() != null && attributes.getEtag().equals(urlConn.getRequestProperty("ETag"))) ||
+                (lastModified != 0 && lastModified <= attributes.getLastModification());
     }
 
@@ -499,14 +484,3 @@
         finishLoading(LoadResult.CANCELED);
     }
-
-    /*
-     * Temporary fix for file URLs. Returns response code for HttpURLConnections or 200 for all other
-     */
-    private int responseCode(URLConnection urlConn) throws IOException {
-        if (urlConn instanceof HttpURLConnection) {
-            return ((HttpURLConnection) urlConn).getResponseCode();
-        } else {
-            return 200;
-        }
-    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/data/imagery/TMSCachedTileLoader.java	(revision 8602)
@@ -17,6 +17,6 @@
 import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
 import org.openstreetmap.josm.data.cache.HostLimitQueue;
-import org.openstreetmap.josm.data.cache.JCSCachedTileLoaderJob;
 import org.openstreetmap.josm.data.preferences.IntegerProperty;
+import org.openstreetmap.josm.tools.Utils;
 
 /**
@@ -85,5 +85,5 @@
                 TimeUnit.SECONDS,
                 new HostLimitQueue(HOST_LIMIT.get().intValue()),
-                JCSCachedTileLoaderJob.getNamedThreadFactory(name)
+                Utils.getNamedThreadFactory(name)
                 );
     }
Index: /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java	(revision 8602)
@@ -20,4 +20,6 @@
 import java.io.File;
 import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
@@ -56,4 +58,5 @@
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.RenameLayerAction;
@@ -129,5 +132,5 @@
 
     protected TileCache tileCache;
-    protected TileSource tileSource;
+    protected AbstractTMSTileSource tileSource;
     protected TileLoader tileLoader;
 
@@ -151,5 +154,5 @@
      * @throws IllegalArgumentException when Imagery is not supported by layer
      */
-    protected abstract TileSource getTileSource(ImageryInfo info) throws IllegalArgumentException;
+    protected abstract AbstractTMSTileSource getTileSource(ImageryInfo info) throws IllegalArgumentException;
 
     protected Map<String, String> getHeaders(TileSource tileSource) {
@@ -160,5 +163,5 @@
     }
 
-    protected void initTileSource(TileSource tileSource) {
+    protected void initTileSource(AbstractTMSTileSource tileSource) {
         attribution.initialize(tileSource);
 
@@ -173,4 +176,15 @@
             tileCache = new MemoryTileCache();
         }
+
+        try {
+            if ("file".equalsIgnoreCase(new URL(tileSource.getBaseUrl()).getProtocol())) {
+                tileLoader = new OsmTileLoader(this);
+                tileCache = new MemoryTileCache();
+            }
+        } catch (MalformedURLException e) {
+            // ignore, assume that this is not a file
+        }
+
+
         if (tileLoader == null)
             tileLoader = new OsmTileLoader(this);
Index: /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/TMSLayer.java	(revision 8602)
@@ -6,5 +6,5 @@
 import org.apache.commons.jcs.access.CacheAccess;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
-import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
 import org.openstreetmap.gui.jmapviewer.tilesources.ScanexTileSource;
 import org.openstreetmap.gui.jmapviewer.tilesources.TMSTileSource;
@@ -66,5 +66,5 @@
      */
     @Override
-    protected TileSource getTileSource(ImageryInfo info) throws IllegalArgumentException {
+    protected AbstractTMSTileSource getTileSource(ImageryInfo info) throws IllegalArgumentException {
         return getTileSourceStatic(info);
     }
@@ -96,5 +96,5 @@
      * @throws IllegalArgumentException if url from imagery info is null or invalid
      */
-    public static TileSource getTileSourceStatic(ImageryInfo info) throws IllegalArgumentException {
+    public static AbstractTMSTileSource getTileSourceStatic(ImageryInfo info) throws IllegalArgumentException {
         if (info.getImageryType() == ImageryType.TMS) {
             TemplatedTMSTileSource.checkUrl(info.getUrl());
Index: /trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/WMSLayer.java	(revision 8602)
@@ -18,4 +18,5 @@
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
@@ -73,5 +74,5 @@
 
     @Override
-    protected TileSource getTileSource(ImageryInfo info) {
+    protected AbstractTMSTileSource getTileSource(ImageryInfo info) {
         if (info.getImageryType() == ImageryType.WMS && info.getUrl() != null) {
             TemplatedWMSTileSource.checkUrl(info.getUrl());
Index: /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/gui/layer/WMTSLayer.java	(revision 8602)
@@ -8,5 +8,5 @@
 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
 import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
-import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
+import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.cache.BufferedImageCacheEntry;
@@ -48,5 +48,5 @@
 
     @Override
-    protected TileSource getTileSource(ImageryInfo info) {
+    protected AbstractTMSTileSource getTileSource(ImageryInfo info) {
         try {
             if (info.getImageryType() == ImageryType.WMTS && info.getUrl() != null) {
Index: /trunk/src/org/openstreetmap/josm/tools/Utils.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 8601)
+++ /trunk/src/org/openstreetmap/josm/tools/Utils.java	(revision 8602)
@@ -46,4 +46,5 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
@@ -1370,5 +1371,5 @@
      * Returns the initial capacity to pass to the HashMap / HashSet constructor
      * when it is initialized with a known number of entries.
-     * 
+     *
      * When a HashMap is filled with entries, the underlying array is copied over
      * to a larger one multiple times. To avoid this process when the number of
@@ -1387,5 +1388,5 @@
      * Returns the initial capacity to pass to the HashMap / HashSet constructor
      * when it is initialized with a known number of entries.
-     * 
+     *
      * When a HashMap is filled with entries, the underlying array is copied over
      * to a larger one multiple times. To avoid this process when the number of
@@ -1393,5 +1394,5 @@
      * given to the HashMap constructor. This method returns a suitable value
      * that avoids rehashing but doesn't waste memory.
-     * 
+     *
      * Assumes default load factor (0.75).
      * @param nEntries the number of entries expected
@@ -1401,3 +1402,18 @@
         return hashMapInitialCapacity(nEntries, 0.75f);
     }
+
+    /**
+     * @param name to be set for the threads
+     * @return Thread Factory returning named threads
+     */
+    public static ThreadFactory getNamedThreadFactory(final String name) {
+        return new ThreadFactory() {
+            @Override
+            public Thread newThread(Runnable r) {
+                Thread t = Executors.defaultThreadFactory().newThread(r);
+                t.setName(name);
+                return t;
+            }
+        };
+    }
 }
