1 package tim.prune.gui.map;
4 import java.awt.image.ImageObserver;
5 import java.net.MalformedURLException;
8 import tim.prune.config.Config;
11 * Class responsible for managing the map tiles,
12 * including invoking the correct memory cacher(s) and/or disk cacher(s)
14 public class MapTileManager implements ImageObserver
16 /** Parent object to inform when tiles received */
17 private MapCanvas _parent = null;
18 /** Current map source */
19 private MapSource _mapSource = null;
20 /** Array of tile caches, one per layer */
21 private MemTileCacher[] _tempCaches = null;
22 /** Number of layers */
23 private int _numLayers = -1;
24 /** Current zoom level */
25 private int _zoom = 0;
26 /** Number of tiles in each direction for this zoom level */
27 private int _numTileIndices = 1;
32 * @param inParent parent canvas to be informed of updates
34 public MapTileManager(MapCanvas inParent)
37 // Adjust the index of the selected map source
44 * @param inZoom zoom level
45 * @param inTileX x coord of central tile
46 * @param inTileY y coord of central tile
48 public void centreMap(int inZoom, int inTileX, int inTileY)
51 // Calculate number of tiles = 2^^zoom
52 _numTileIndices = 1 << _zoom;
53 // Pass params onto all memory cachers
54 if (_tempCaches != null) {
55 for (int i=0; i<_tempCaches.length; i++) {
56 _tempCaches[i].centreMap(inZoom, inTileX, inTileY);
62 * @return true if zoom is too high for tiles
64 public boolean isOverzoomed()
66 // Ask current map source what maximum zoom is
67 int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
68 return (_zoom > maxZoom);
72 * Clear all the memory caches due to changed config / zoom
74 public void clearMemoryCaches()
76 int numLayers = _mapSource.getNumLayers();
77 if (_tempCaches == null || _tempCaches.length != numLayers)
79 // Cachers don't match, so need to create the right number of them
80 _tempCaches = new MemTileCacher[numLayers];
81 for (int i=0; i<numLayers; i++) {
82 _tempCaches[i] = new MemTileCacher();
86 // Cachers already there, just need to be cleared
87 for (int i=0; i<numLayers; i++) {
88 _tempCaches[i].clearAll();
94 * Reset the map source configuration, apparently it has changed
96 public void resetConfig()
98 int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
99 _mapSource = MapSourceLibrary.getSource(sourceNum);
100 if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
102 _numLayers = _mapSource.getNumLayers();
106 * Adjust the index of the selected map
107 * (only required if config was loaded from a previous version of GpsPrune)
109 private void adjustSelectedMap()
111 int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
112 int prevNumFixed = Config.getConfigInt(Config.KEY_NUM_FIXED_MAPS);
113 // Number of fixed maps not specified in version <=13, default to 6
114 if (prevNumFixed == 0) prevNumFixed = 6;
115 int currNumFixed = MapSourceLibrary.getNumFixedSources();
116 // Only need to do something if the number has changed
117 if (currNumFixed != prevNumFixed && (sourceNum >= prevNumFixed || sourceNum >= currNumFixed))
119 sourceNum += (currNumFixed - prevNumFixed);
120 Config.setConfigInt(Config.KEY_MAPSOURCE_INDEX, sourceNum);
122 Config.setConfigInt(Config.KEY_NUM_FIXED_MAPS, currNumFixed);
126 * @return the number of layers in the map
128 public int getNumLayers()
134 * @param inLayer layer number, starting from 0
135 * @param inX x index of tile
136 * @param inY y index of tile
137 * @return selected tile if already loaded, or null otherwise
139 public Image getTile(int inLayer, int inX, int inY)
141 if (inY < 0 || inY >= _numTileIndices) return null;
142 // Wrap tile indices which are too big or too small
143 inX = ((inX % _numTileIndices) + _numTileIndices) % _numTileIndices;
145 // Check first in memory cache for tile
146 MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
147 Image tile = tempCache.getTile(inX, inY);
152 // Tile wasn't in memory, but maybe it's in disk cache (if there is one)
153 String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
154 boolean useDisk = (diskCachePath != null);
155 boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
158 tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
161 // Pass tile to memory cache
162 tempCache.setTile(tile, inX, inY, _zoom);
163 if (tile.getWidth(this) > 0) {return tile;}
167 // Tile wasn't in memory or on disk, so if online let's get it
172 URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
173 if (useDisk && DiskTileCacher.saveTile(tileUrl, diskCachePath,
174 _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this))
176 // Image now copied directly from URL stream to disk cache
180 // Load image asynchronously, using observer
181 // tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
182 // In order to set the http user agent, need to use a TileDownloader instead
183 TileDownloader.triggerLoad(this, tileUrl, inLayer, inX, inY, _zoom);
186 catch (MalformedURLException urle) {} // ignore
192 * Method called by image loader to inform of updates to the tiles
193 * @param img the image
194 * @param infoflags flags describing how much of the image is known
197 * @param width ignored
198 * @param height ignored
199 * @return false to carry on loading, true to stop
201 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
203 boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
204 boolean error = (infoflags & ImageObserver.ERROR) > 0;
205 if (loaded || error) {
206 _parent.tilesUpdated(loaded);
212 * Callback method from TileDownloader to let us know that an image has been loaded
213 * @param inTile Loaded Image object
214 * @param inLayer layer index from 0
215 * @param inX x coordinate of tile
216 * @param inY y coordinate of tile
217 * @param inZoom zoom level of loaded image
219 public void notifyImageLoaded(Image inTile, int inLayer, int inX, int inY, int inZoom)
223 MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
224 if (tempCache.getTile(inX, inY) == null)
226 // Check with cache that the zoom level is still valid
227 tempCache.setTile(inTile, inX, inY, inZoom);
228 inTile.getWidth(this); // trigger imageUpdate when image is ready