]> gitweb.fperrin.net Git - GpsPrune.git/blobdiff - tim/prune/gui/map/MapTileManager.java
Version 16, February 2014
[GpsPrune.git] / tim / prune / gui / map / MapTileManager.java
index f7a281b1022ca8059a02e4fe9aef004431b464fc..ed8849bd469118f5314322adbe77c1ba097523f4 100644 (file)
@@ -1,39 +1,44 @@
 package tim.prune.gui.map;
 
 import java.awt.Image;
-import java.awt.Toolkit;
 import java.awt.image.ImageObserver;
 import java.net.MalformedURLException;
 import java.net.URL;
 
 import tim.prune.config.Config;
 
+
 /**
  * Class responsible for managing the map tiles,
  * including invoking the correct memory cacher(s) and/or disk cacher(s)
  */
 public class MapTileManager implements ImageObserver
 {
-       /** Parent object to inform when tiles received */
-       private MapCanvas _parent = null;
+       /** Consumer object to inform when tiles received */
+       private TileConsumer _consumer = null;
        /** Current map source */
        private MapSource _mapSource = null;
        /** Array of tile caches, one per layer */
        private MemTileCacher[] _tempCaches = null;
+       /** Flag for whether to download any tiles or just pull from disk */
+       private boolean _downloadTiles = true;
+       /** Flag for whether to return incomplete images or just pass to tile cache until they're done */
+       private boolean _returnIncompleteImages = false;
        /** Number of layers */
        private int _numLayers = -1;
        /** Current zoom level */
        private int _zoom = 0;
+       /** Number of tiles in each direction for this zoom level */
+       private int _numTileIndices = 1;
 
 
        /**
         * Constructor
-        * @param inParent parent canvas to be informed of updates
+        * @param inConsumer consumer object to be notified
         */
-       public MapTileManager(MapCanvas inParent)
+       public MapTileManager(TileConsumer inConsumer)
        {
-               _parent = inParent;
-               resetConfig();
+               _consumer = inConsumer;
        }
 
        /**
@@ -44,7 +49,7 @@ public class MapTileManager implements ImageObserver
         */
        public void centreMap(int inZoom, int inTileX, int inTileY)
        {
-               _zoom = inZoom;
+               setZoom(inZoom);
                // Pass params onto all memory cachers
                if (_tempCaches != null) {
                        for (int i=0; i<_tempCaches.length; i++) {
@@ -53,6 +58,14 @@ public class MapTileManager implements ImageObserver
                }
        }
 
+       /** @param inZoom zoom level to set */
+       public void setZoom(int inZoom)
+       {
+               _zoom = inZoom;
+               // Calculate number of tiles = 2^^zoom
+               _numTileIndices = 1 << _zoom;
+       }
+
        /**
         * @return true if zoom is too high for tiles
         */
@@ -63,14 +76,30 @@ public class MapTileManager implements ImageObserver
                return (_zoom > maxZoom);
        }
 
+       /**
+        * Enable or disable tile downloading
+        * @param inEnabled true to enable downloading, false to just get tiles from disk
+        */
+       public void enableTileDownloading(boolean inEnabled)
+       {
+               _downloadTiles = inEnabled;
+       }
+
+       /** Configure to return incomplete images instead of going via caches (and another call) */
+       public void setReturnIncompleteImages()
+       {
+               _returnIncompleteImages = true;
+       }
+
        /**
         * Clear all the memory caches due to changed config / zoom
         */
        public void clearMemoryCaches()
        {
                int numLayers = _mapSource.getNumLayers();
-               if (_tempCaches == null || _tempCaches.length != numLayers) {
-                       // Ccahers don't match, so need to create the right number of them
+               if (_tempCaches == null || _tempCaches.length != numLayers)
+               {
+                       // Cachers don't match, so need to create the right number of them
                        _tempCaches = new MemTileCacher[numLayers];
                        for (int i=0; i<numLayers; i++) {
                                _tempCaches[i] = new MemTileCacher();
@@ -85,12 +114,19 @@ public class MapTileManager implements ImageObserver
        }
 
        /**
-        * Reset the map source configuration, apparently it has changed
+        * @param inSourceNum selected map source index
+        */
+       public void setMapSource(int inSourceNum)
+       {
+               setMapSource(MapSourceLibrary.getSource(inSourceNum));
+       }
+
+       /**
+        * @param inMapSource selected map source
         */
-       public void resetConfig()
+       public void setMapSource(MapSource inMapSource)
        {
-               int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
-               _mapSource = MapSourceLibrary.getSource(sourceNum);
+               _mapSource = inMapSource;
                if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
                clearMemoryCaches();
                _numLayers = _mapSource.getNumLayers();
@@ -105,18 +141,29 @@ public class MapTileManager implements ImageObserver
        }
 
        /**
+        * Get a tile from the currently selected map source
         * @param inLayer layer number, starting from 0
         * @param inX x index of tile
         * @param inY y index of tile
+        * @param inDownloadIfNecessary true to download the file if it's not available
         * @return selected tile if already loaded, or null otherwise
         */
-       public Image getTile(int inLayer, int inX, int inY)
+       public Image getTile(int inLayer, int inX, int inY, boolean inDownloadIfNecessary)
        {
+               if (inY < 0 || inY >= _numTileIndices) return null;
+               // Wrap tile indices which are too big or too small
+               inX = ((inX % _numTileIndices) + _numTileIndices) % _numTileIndices;
+
                // Check first in memory cache for tile
-               MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
-               Image tile = tempCache.getTile(inX, inY);
-               if (tile != null) {
-                       return tile;
+               Image tile = null;
+               MemTileCacher tempCache = null;
+               if (_tempCaches != null)
+               {
+                       tempCache = _tempCaches[inLayer]; // Should probably guard array indexes here
+                       tile = tempCache.getTile(inX, inY);
+                       if (tile != null) {
+                               return tile;
+                       }
                }
 
                // Tile wasn't in memory, but maybe it's in disk cache (if there is one)
@@ -128,18 +175,23 @@ public class MapTileManager implements ImageObserver
                        tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
                        if (tile != null)
                        {
+                               if (_returnIncompleteImages) {return tile;}
                                // Pass tile to memory cache
-                               tempCache.setTile(tile, inX, inY);
+                               if (tempCache != null) {
+                                       tempCache.setTile(tile, inX, inY, _zoom);
+                               }
                                if (tile.getWidth(this) > 0) {return tile;}
                                return null;
                        }
+                       // else System.out.println("DTC gave null tile for " + _zoom + ", " + inX + ", " + inY);
                }
                // Tile wasn't in memory or on disk, so if online let's get it
-               if (onlineMode)
+               if (onlineMode && _downloadTiles && inDownloadIfNecessary)
                {
                        try
                        {
                                URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
+                               // System.out.println("Going to fetch: " + tileUrl);
                                if (useDisk && DiskTileCacher.saveTile(tileUrl, diskCachePath,
                                        _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this))
                                {
@@ -148,10 +200,8 @@ public class MapTileManager implements ImageObserver
                                else
                                {
                                        // Load image asynchronously, using observer
-                                       tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
-                                       // Pass to memory cache
-                                       _tempCaches[inLayer].setTile(tile, inX, inY);
-                                       if (tile.getWidth(this) > 0) {return tile;}
+                                       // In order to set the http user agent, need to use a TileDownloader instead
+                                       TileDownloader.triggerLoad(this, tileUrl, inLayer, inX, inY, _zoom);
                                }
                        }
                        catch (MalformedURLException urle) {} // ignore
@@ -174,8 +224,33 @@ public class MapTileManager implements ImageObserver
                boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
                boolean error = (infoflags & ImageObserver.ERROR) > 0;
                if (loaded || error) {
-                       _parent.tilesUpdated(loaded);
+                       _consumer.tilesUpdated(loaded);
                }
                return !loaded;
        }
+
+       /**
+        * Callback method from TileDownloader to let us know that an image has been loaded
+        * @param inTile Loaded Image object
+        * @param inLayer layer index from 0
+        * @param inX x coordinate of tile
+        * @param inY y coordinate of tile
+        * @param inZoom zoom level of loaded image
+        */
+       public void notifyImageLoaded(Image inTile, int inLayer, int inX, int inY, int inZoom)
+       {
+               if (inTile != null && _tempCaches != null)
+               {
+                       MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
+                       if (tempCache.getTile(inX, inY) == null)
+                       {
+                               // Check with cache that the zoom level is still valid
+                               tempCache.setTile(inTile, inX, inY, inZoom);
+                               inTile.getWidth(this); // trigger imageUpdate when image is ready
+                       }
+               }
+               else if (inTile != null) {
+                       inTile.getWidth(this);
+               }
+       }
 }