X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fgui%2Fmap%2FMapTileManager.java;h=f7370c5c90c833e7f053fc786eafdae37ab7f843;hb=79f3ca2954d7feb6052c21b3aa974c89b2b101d6;hp=9f1fbfe70f8ccde2ca78d87240dc48fb51ef923a;hpb=c0387c124840c9407e040600fda88f3c3e8f6aa6;p=GpsPrune.git diff --git a/tim/prune/gui/map/MapTileManager.java b/tim/prune/gui/map/MapTileManager.java index 9f1fbfe..f7370c5 100644 --- a/tim/prune/gui/map/MapTileManager.java +++ b/tim/prune/gui/map/MapTileManager.java @@ -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= _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 tileImage = null; + MemTileCacher tempCache = null; + if (_tempCaches != null) + { + tempCache = _tempCaches[inLayer]; // Should probably guard array indexes here + tileImage = tempCache.getTile(inX, inY); + if (tileImage != null) { + return tileImage; + } } // Tile wasn't in memory, but maybe it's in disk cache (if there is one) String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE); boolean useDisk = (diskCachePath != null); boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE); + MapTile mapTile = null; if (useDisk) { - tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode); - if (tile != null) { + // Get the map tile from cache + mapTile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY)); + if (mapTile != null && mapTile.getImage() != null) + { + tileImage = mapTile.getImage(); + if (_returnIncompleteImages) {return tileImage;} // Pass tile to memory cache - tempCache.setTile(tile, inX, inY); - if (tile.getWidth(this) > 0) {return tile;} - return null; + if (tempCache != null) { + tempCache.setTile(tileImage, inX, inY, _zoom); + } + tileImage.getWidth(this); // trigger the load from file } } - // Tile wasn't in memory or on disk, so if online let's get it - if (onlineMode) + // Maybe we've got an image now, maybe it's expired + final boolean shouldDownload = (tileImage == null || mapTile == null || mapTile.isExpired()); + + // If we're online then try to download the tile + if (onlineMode && _downloadTiles && inDownloadIfNecessary && shouldDownload) { try { URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY)); - if (useDisk) { - // Copy image directly from URL stream to disk cache - DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this); + //System.out.println("Trying to fetch: " + tileUrl); + if (useDisk) + { + DiskTileCacher.saveTile(tileUrl, diskCachePath, + _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this); + // Image will now be copied directly from URL stream to disk cache } - else { + 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 } - return null; + return tileImage; } /** @@ -171,8 +229,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); + } + } }