]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/map/MapTileManager.java
Version 13, August 2011
[GpsPrune.git] / tim / prune / gui / map / MapTileManager.java
1 package tim.prune.gui.map;
2
3 import java.awt.Image;
4 import java.awt.Toolkit;
5 import java.awt.image.ImageObserver;
6 import java.net.MalformedURLException;
7 import java.net.URL;
8
9 import tim.prune.config.Config;
10
11 /**
12  * Class responsible for managing the map tiles,
13  * including invoking the correct memory cacher(s) and/or disk cacher(s)
14  */
15 public class MapTileManager implements ImageObserver
16 {
17         /** Parent object to inform when tiles received */
18         private MapCanvas _parent = null;
19         /** Current map source */
20         private MapSource _mapSource = null;
21         /** Array of tile caches, one per layer */
22         private MemTileCacher[] _tempCaches = null;
23         /** Number of layers */
24         private int _numLayers = -1;
25         /** Current zoom level */
26         private int _zoom = 0;
27
28
29         /**
30          * Constructor
31          * @param inParent parent canvas to be informed of updates
32          */
33         public MapTileManager(MapCanvas inParent)
34         {
35                 _parent = inParent;
36                 resetConfig();
37         }
38
39         /**
40          * Recentre the map
41          * @param inZoom zoom level
42          * @param inTileX x coord of central tile
43          * @param inTileY y coord of central tile
44          */
45         public void centreMap(int inZoom, int inTileX, int inTileY)
46         {
47                 _zoom = inZoom;
48                 // Pass params onto all memory cachers
49                 if (_tempCaches != null) {
50                         for (int i=0; i<_tempCaches.length; i++) {
51                                 _tempCaches[i].centreMap(inZoom, inTileX, inTileY);
52                         }
53                 }
54         }
55
56         /**
57          * @return true if zoom is too high for tiles
58          */
59         public boolean isOverzoomed()
60         {
61                 // Ask current map source what maximum zoom is
62                 int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
63                 return (_zoom > maxZoom);
64         }
65
66         /**
67          * Clear all the memory caches due to changed config / zoom
68          */
69         public void clearMemoryCaches()
70         {
71                 int numLayers = _mapSource.getNumLayers();
72                 if (_tempCaches == null || _tempCaches.length != numLayers) {
73                         // Ccahers don't match, so need to create the right number of them
74                         _tempCaches = new MemTileCacher[numLayers];
75                         for (int i=0; i<numLayers; i++) {
76                                 _tempCaches[i] = new MemTileCacher();
77                         }
78                 }
79                 else {
80                         // Cachers already there, just need to be cleared
81                         for (int i=0; i<numLayers; i++) {
82                                 _tempCaches[i].clearAll();
83                         }
84                 }
85         }
86
87         /**
88          * Reset the map source configuration, apparently it has changed
89          */
90         public void resetConfig()
91         {
92                 int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
93                 _mapSource = MapSourceLibrary.getSource(sourceNum);
94                 if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
95                 clearMemoryCaches();
96                 _numLayers = _mapSource.getNumLayers();
97         }
98
99         /**
100          * @return the number of layers in the map
101          */
102         public int getNumLayers()
103         {
104                 return _numLayers;
105         }
106
107         /**
108          * @param inLayer layer number, starting from 0
109          * @param inX x index of tile
110          * @param inY y index of tile
111          * @return selected tile if already loaded, or null otherwise
112          */
113         public Image getTile(int inLayer, int inX, int inY)
114         {
115                 // Check first in memory cache for tile
116                 MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
117                 Image tile = tempCache.getTile(inX, inY);
118                 if (tile != null) {
119                         return tile;
120                 }
121
122                 // Tile wasn't in memory, but maybe it's in disk cache (if there is one)
123                 String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
124                 boolean useDisk = (diskCachePath != null);
125                 boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
126                 if (useDisk)
127                 {
128                         tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
129                         if (tile != null)
130                         {
131                                 // Pass tile to memory cache
132                                 tempCache.setTile(tile, inX, inY);
133                                 if (tile.getWidth(this) > 0) {return tile;}
134                                 return null;
135                         }
136                 }
137                 // Tile wasn't in memory or on disk, so if online let's get it
138                 if (onlineMode)
139                 {
140                         try
141                         {
142                                 URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
143                                 if (useDisk && DiskTileCacher.saveTile(tileUrl, diskCachePath,
144                                         _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this))
145                                 {
146                                         // Image now copied directly from URL stream to disk cache
147                                 }
148                                 else
149                                 {
150                                         // Load image asynchronously, using observer
151                                         tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
152                                         // Pass to memory cache
153                                         _tempCaches[inLayer].setTile(tile, inX, inY);
154                                         if (tile.getWidth(this) > 0) {return tile;}
155                                 }
156                         }
157                         catch (MalformedURLException urle) {} // ignore
158                 }
159                 return null;
160         }
161
162         /**
163          * Method called by image loader to inform of updates to the tiles
164          * @param img the image
165          * @param infoflags flags describing how much of the image is known
166          * @param x ignored
167          * @param y ignored
168          * @param width ignored
169          * @param height ignored
170          * @return false to carry on loading, true to stop
171          */
172         public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
173         {
174                 boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
175                 boolean error = (infoflags & ImageObserver.ERROR) > 0;
176                 if (loaded || error) {
177                         _parent.tilesUpdated(loaded);
178                 }
179                 return !loaded;
180         }
181 }