]> gitweb.fperrin.net Git - GpsPrune.git/blob - tim/prune/gui/map/MapTileManager.java
Version 10, May 2010
[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                                 // Pass tile to memory cache
131                                 tempCache.setTile(tile, inX, inY);
132                                 if (tile.getWidth(this) > 0) {return tile;}
133                                 return null;
134                         }
135                 }
136                 // Tile wasn't in memory or on disk, so if online let's get it
137                 if (onlineMode)
138                 {
139                         try
140                         {
141                                 URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
142                                 if (useDisk) {
143                                         // Copy image directly from URL stream to disk cache
144                                         DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this);
145                                 }
146                                 else {
147                                         // Load image asynchronously, using observer
148                                         tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
149                                         // Pass to memory cache
150                                         _tempCaches[inLayer].setTile(tile, inX, inY);
151                                         if (tile.getWidth(this) > 0) {return tile;}
152                                 }
153                         }
154                         catch (MalformedURLException urle) {} // ignore
155                 }
156                 return null;
157         }
158
159         /**
160          * Method called by image loader to inform of updates to the tiles
161          * @param img the image
162          * @param infoflags flags describing how much of the image is known
163          * @param x ignored
164          * @param y ignored
165          * @param width ignored
166          * @param height ignored
167          * @return false to carry on loading, true to stop
168          */
169         public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
170         {
171                 boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
172                 boolean error = (infoflags & ImageObserver.ERROR) > 0;
173                 if (loaded || error) {
174                         _parent.tilesUpdated(loaded);
175                 }
176                 return !loaded;
177         }
178 }