]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Add OSM GPS Tiles in default data config
[andy/viking.git] / src / vikmapslayer.c
1 /*
2  * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3  *
4  * Copyright (C) 2005, Evan Battaglia <viking@greentorch.org>
5  * Copyright (C) 2010, Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
6  * Copyright (c) 2013, Rob Norris <rw_norris@hotmail.com>
7  * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
8  * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include <gdk-pixbuf/gdk-pixdata.h>
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #include <glib/gi18n.h>
35
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
39 #ifdef HAVE_MATH_H
40 #include <math.h>
41 #endif
42
43 #ifdef HAVE_UNISTD_H
44 #include <unistd.h>
45 #endif
46
47 #include "viking.h"
48 #include "vikmapsourcedefault.h"
49 #include "maputils.h"
50 #include "mapcache.h"
51 #include "background.h"
52 #include "preferences.h"
53 #include "vikmapslayer.h"
54 #include "icons/icons.h"
55 #include "metatile.h"
56 #include "ui_util.h"
57 #include "map_ids.h"
58
59 #ifdef HAVE_SQLITE3_H
60 #include "sqlite3.h"
61 #include <gio/gio.h>
62 #endif
63
64 #define VIK_SETTINGS_MAP_MAX_TILES "maps_max_tiles"
65 static gint MAX_TILES = 1000;
66
67 #define VIK_SETTINGS_MAP_MIN_SHRINKFACTOR "maps_min_shrinkfactor"
68 #define VIK_SETTINGS_MAP_MAX_SHRINKFACTOR "maps_max_shrinkfactor"
69 static gdouble MAX_SHRINKFACTOR = 8.0000001; /* zoom 1 viewing 8-tiles */
70 static gdouble MIN_SHRINKFACTOR = 0.0312499; /* zoom 32 viewing 1-tiles */
71
72 #define VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR "maps_real_min_shrinkfactor"
73 static gdouble REAL_MIN_SHRINKFACTOR = 0.0039062499; /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
74
75 #define VIK_SETTINGS_MAP_SCALE_INC_UP "maps_scale_inc_up"
76 static guint SCALE_INC_UP = 2;
77 #define VIK_SETTINGS_MAP_SCALE_INC_DOWN "maps_scale_inc_down"
78 static guint SCALE_INC_DOWN = 4;
79 #define VIK_SETTINGS_MAP_SCALE_SMALLER_ZOOM_FIRST "maps_scale_smaller_zoom_first"
80 static gboolean SCALE_SMALLER_ZOOM_FIRST = TRUE;
81
82 /****** MAP TYPES ******/
83
84 static GList *__map_types = NULL;
85
86 #define NUM_MAP_TYPES g_list_length(__map_types)
87
88 /* List of label for each map type */
89 static gchar **params_maptypes = NULL;
90
91 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
92 static guint *params_maptypes_ids = NULL;
93
94 /******** MAPZOOMS *********/
95
96 static gchar *params_mapzooms[] = { N_("Use Viking Zoom Level"), "0.25", "0.5", "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "USGS 10k", "USGS 24k", "USGS 25k", "USGS 50k", "USGS 100k", "USGS 200k", "USGS 250k", NULL };
97 static gdouble __mapzooms_x[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
98 static gdouble __mapzooms_y[] = { 0.0, 0.25, 0.5, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.0, 128.0, 256.0, 512.0, 1024.0, 1.016, 2.4384, 2.54, 5.08, 10.16, 20.32, 25.4 };
99
100 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
101
102 /**************************/
103
104
105 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
106 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
107 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
108 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
109 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
110 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
111 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values );
112 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
113 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
114 static void maps_layer_free ( VikMapsLayer *vml );
115 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
116 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
117 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
118 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
119 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
120 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
121 static guint map_uniq_id_to_index ( guint uniq_id );
122
123
124 static VikLayerParamScale params_scales[] = {
125   /* min, max, step, digits (decimal places) */
126  { 0, 255, 3, 0 }, /* alpha */
127 };
128
129 static VikLayerParamData id_default ( void ) { return VIK_LPD_UINT ( MAP_ID_MAPBOX_OUTDOORS ); }
130 static VikLayerParamData directory_default ( void )
131 {
132   VikLayerParamData data;
133   VikLayerParamData *pref = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir");
134   if (pref) data.s = g_strdup ( pref->s ); else data.s = "";
135   return data;
136 }
137 static VikLayerParamData file_default ( void )
138 {
139   VikLayerParamData data;
140   data.s = "";
141   return data;
142 }
143 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
144 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
145
146 static gchar *cache_types[] = { "Viking", N_("OSM"), NULL };
147 static VikMapsCacheLayout cache_layout_default_value = VIK_MAPS_CACHE_LAYOUT_VIKING;
148 static VikLayerParamData cache_layout_default ( void ) { return VIK_LPD_UINT ( cache_layout_default_value ); }
149
150 VikLayerParam maps_layer_params[] = {
151   // NB mode => id - But can't break file format just to rename something better
152   { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, id_default, NULL, NULL },
153   { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default, NULL, NULL },
154   { VIK_LAYER_MAPS, "cache_type", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Cache Layout:"), VIK_LAYER_WIDGET_COMBOBOX, cache_types, NULL, 
155     N_("This determines the tile storage layout on disk"), cache_layout_default, NULL, NULL },
156   { VIK_LAYER_MAPS, "mapfile", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Map File:"), VIK_LAYER_WIDGET_FILEENTRY, GINT_TO_POINTER(VF_FILTER_MBTILES), NULL,
157     N_("An MBTiles file. Only applies when the map type method is 'MBTiles'"), file_default, NULL, NULL },
158   { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
159     N_("Control the Alpha value for transparency effects"), alpha_default, NULL, NULL },
160   { VIK_LAYER_MAPS, "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default, NULL, NULL },
161   { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
162     N_("Using this option avoids attempting to update already acquired tiles. This can be useful if you want to restrict the network usage, without having to resort to manual control. Only applies when 'Autodownload Maps' is on."), vik_lpd_false_default, NULL, NULL },
163   { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
164     N_("Determines the method of displaying map tiles for the current zoom level. 'Viking Zoom Level' uses the best matching level, otherwise setting a fixed value will always use map tiles of the specified value regardless of the actual zoom level."),
165     mapzoom_default, NULL, NULL },
166 };
167
168 enum {
169   PARAM_MAPTYPE=0,
170   PARAM_CACHE_DIR,
171   PARAM_CACHE_LAYOUT,
172   PARAM_FILE,
173   PARAM_ALPHA,
174   PARAM_AUTODOWNLOAD,
175   PARAM_ONLYMISSING,
176   PARAM_MAPZOOM,
177   NUM_PARAMS
178 };
179
180 void maps_layer_set_autodownload_default ( gboolean autodownload )
181 {
182   // Set appropriate function
183   if ( autodownload )
184     maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_true_default;
185   else
186     maps_layer_params[PARAM_AUTODOWNLOAD].default_value = vik_lpd_false_default;
187 }
188
189 void maps_layer_set_cache_default ( VikMapsCacheLayout layout )
190 {
191   // Override default value returned by the default param function
192   cache_layout_default_value = layout;
193 }
194
195 static VikToolInterface maps_tools[] = {
196   { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
197     (VikToolConstructorFunc) maps_layer_download_create,
198     NULL,
199     NULL,
200     NULL,
201     (VikToolMouseFunc) maps_layer_download_click,
202     NULL,
203     (VikToolMouseFunc) maps_layer_download_release,
204     NULL,
205     FALSE,
206     GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf, NULL },
207 };
208
209 VikLayerInterface vik_maps_layer_interface = {
210   "Map",
211   N_("Map"),
212   "<control><shift>M",
213   &vikmapslayer_pixbuf,
214
215   maps_tools,
216   sizeof(maps_tools) / sizeof(maps_tools[0]),
217
218   maps_layer_params,
219   NUM_PARAMS,
220   NULL,
221   0,
222
223   VIK_MENU_ITEM_ALL,
224
225   (VikLayerFuncCreate)                  maps_layer_new,
226   (VikLayerFuncRealize)                 NULL,
227   (VikLayerFuncPostRead)                maps_layer_post_read,
228   (VikLayerFuncFree)                    maps_layer_free,
229
230   (VikLayerFuncProperties)              NULL,
231   (VikLayerFuncDraw)                    maps_layer_draw,
232   (VikLayerFuncChangeCoordMode)         NULL,
233
234   (VikLayerFuncGetTimestamp)            NULL,
235
236   (VikLayerFuncSetMenuItemsSelection)   NULL,
237   (VikLayerFuncGetMenuItemsSelection)   NULL,
238
239   (VikLayerFuncAddMenuItems)            maps_layer_add_menu_items,
240   (VikLayerFuncSublayerAddMenuItems)    NULL,
241
242   (VikLayerFuncSublayerRenameRequest)   NULL,
243   (VikLayerFuncSublayerToggleVisible)   NULL,
244   (VikLayerFuncSublayerTooltip)         NULL,
245   (VikLayerFuncLayerTooltip)            maps_layer_tooltip,
246   (VikLayerFuncLayerSelected)           NULL,
247
248   (VikLayerFuncMarshall)                maps_layer_marshall,
249   (VikLayerFuncUnmarshall)              maps_layer_unmarshall,
250
251   (VikLayerFuncSetParam)                maps_layer_set_param,
252   (VikLayerFuncGetParam)                maps_layer_get_param,
253   (VikLayerFuncChangeParam)             maps_layer_change_param,
254
255   (VikLayerFuncReadFileData)            NULL,
256   (VikLayerFuncWriteFileData)           NULL,
257
258   (VikLayerFuncDeleteItem)              NULL,
259   (VikLayerFuncCutItem)                 NULL,
260   (VikLayerFuncCopyItem)                NULL,
261   (VikLayerFuncPasteItem)               NULL,
262   (VikLayerFuncFreeCopiedItem)          NULL,
263   (VikLayerFuncDragDropRequest)         NULL,
264
265   (VikLayerFuncSelectClick)             NULL,
266   (VikLayerFuncSelectMove)              NULL,
267   (VikLayerFuncSelectRelease)           NULL,
268   (VikLayerFuncSelectedViewportMenu)    NULL,
269 };
270
271 struct _VikMapsLayer {
272   VikLayer vl;
273   guint maptype;
274   gchar *cache_dir;
275   VikMapsCacheLayout cache_layout;
276   guint8 alpha;
277   guint mapzoom_id;
278   gdouble xmapzoom, ymapzoom;
279
280   gboolean autodownload;
281   gboolean adl_only_missing;
282   VikCoord *last_center;
283   gdouble last_xmpp;
284   gdouble last_ympp;
285
286   gint dl_tool_x, dl_tool_y;
287
288   GtkMenu *dl_right_click_menu;
289   VikCoord redownload_ul, redownload_br; /* right click menu only */
290   VikViewport *redownload_vvp;
291   gchar *filename;
292 #ifdef HAVE_SQLITE3_H
293   sqlite3 *mbtiles;
294 #endif
295 };
296
297 enum { REDOWNLOAD_NONE = 0,    /* download only missing maps */
298        REDOWNLOAD_BAD,         /* download missing and bad maps */
299        REDOWNLOAD_NEW,         /* download missing maps that are newer on server only */
300        REDOWNLOAD_ALL,         /* download all maps */
301        DOWNLOAD_OR_REFRESH };  /* download missing maps and refresh cache */
302
303 static VikLayerParam prefs[] = {
304   { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default map layer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, N_("Choose a directory to store cached Map tiles for this layer"), NULL, NULL, NULL },
305 };
306
307 void maps_layer_init ()
308 {
309   VikLayerParamData tmp;
310   tmp.s = maps_layer_default_dir();
311   a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
312
313   gint max_tiles = MAX_TILES;
314   if ( a_settings_get_integer ( VIK_SETTINGS_MAP_MAX_TILES, &max_tiles ) )
315     MAX_TILES = max_tiles;
316
317   gdouble gdtmp;
318   if ( a_settings_get_double ( VIK_SETTINGS_MAP_MIN_SHRINKFACTOR, &gdtmp ) )
319     MIN_SHRINKFACTOR = gdtmp;
320
321   if ( a_settings_get_double ( VIK_SETTINGS_MAP_MAX_SHRINKFACTOR, &gdtmp ) )
322     MAX_SHRINKFACTOR = gdtmp;
323
324   if ( a_settings_get_double ( VIK_SETTINGS_MAP_REAL_MIN_SHRINKFACTOR, &gdtmp ) )
325     REAL_MIN_SHRINKFACTOR = gdtmp;
326
327   gint gitmp = 0;
328   if ( a_settings_get_integer ( VIK_SETTINGS_MAP_SCALE_INC_UP, &gitmp ) )
329     SCALE_INC_UP = gitmp;
330
331   if ( a_settings_get_integer ( VIK_SETTINGS_MAP_SCALE_INC_DOWN, &gitmp ) )
332     SCALE_INC_DOWN = gitmp;
333
334   gboolean gbtmp = TRUE;
335   if ( a_settings_get_boolean ( VIK_SETTINGS_MAP_SCALE_SMALLER_ZOOM_FIRST, &gbtmp ) )
336     SCALE_SMALLER_ZOOM_FIRST = gbtmp;
337
338 }
339
340 /****************************************/
341 /******** MAPS LAYER TYPES **************/
342 /****************************************/
343
344 void _add_map_source ( guint16 id, const char *label, VikMapSource *map )
345 {
346   gsize len = 0;
347   if (params_maptypes)
348     len = g_strv_length (params_maptypes);
349   /* Add the label */
350   params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
351   params_maptypes[len] = g_strdup (label);
352   params_maptypes[len+1] = NULL;
353
354   /* Add the id */
355   params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
356   params_maptypes_ids[len] = id;
357   params_maptypes_ids[len+1] = 0;
358
359   /* We have to clone */
360   VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
361   /* Register the clone in the list */
362   __map_types = g_list_append(__map_types, clone);
363
364   /* Hack
365      We have to ensure the mode LayerParam references the up-to-date
366      GLists.
367   */
368   /*
369   memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
370   memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
371   */
372   maps_layer_params[0].widget_data = params_maptypes;
373   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
374 }
375
376 void _update_map_source ( const char *label, VikMapSource *map, int index )
377 {
378   GList *item = g_list_nth (__map_types, index);
379   g_object_unref (item->data);
380   item->data = g_object_ref (map);
381   /* Change previous data */
382   g_free (params_maptypes[index]);
383   params_maptypes[index] = g_strdup (label);
384 }
385
386 /**
387  * maps_layer_register_map_source:
388  * @map: the new VikMapSource
389  *
390  * Register a new VikMapSource.
391  * Override existing one (equality of id).
392  */
393 void maps_layer_register_map_source ( VikMapSource *map )
394 {
395   g_assert(map != NULL);
396   
397   guint16 id = vik_map_source_get_uniq_id(map);
398   const char *label = vik_map_source_get_label(map);
399   g_assert(label != NULL);
400
401   int previous = map_uniq_id_to_index (id);
402   if (previous != NUM_MAP_TYPES)
403   {
404     _update_map_source (label, map, previous);
405   }
406   else
407   {
408     _add_map_source (id, label, map);
409   }
410 }
411
412 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
413 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
414 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
415
416 /**
417  * vik_maps_layer_get_map_type:
418  *
419  * Returns the actual map id (rather than the internal type index value)
420  */
421 guint vik_maps_layer_get_map_type(VikMapsLayer *vml)
422 {
423   return MAPS_LAYER_NTH_ID(vml->maptype);
424 }
425
426 /**
427  * vik_maps_layer_set_map_type:
428  *
429  */
430 void vik_maps_layer_set_map_type(VikMapsLayer *vml, guint map_type)
431 {
432    gint maptype = map_uniq_id_to_index(map_type);
433    if ( maptype == NUM_MAP_TYPES )
434       g_warning(_("Unknown map type"));
435    else
436       vml->maptype = maptype;
437 }
438
439 /**
440  * vik_maps_layer_get_default_map_type:
441  *
442  */
443 guint vik_maps_layer_get_default_map_type ()
444 {
445   VikLayerInterface *vli = vik_layer_get_interface ( VIK_LAYER_MAPS );
446   VikLayerParamData vlpd = a_layer_defaults_get ( vli->fixed_layer_name, "mode", VIK_LAYER_PARAM_UINT );
447   if ( vlpd.u == 0 )
448     vlpd = id_default();
449   return vlpd.u;
450 }
451
452 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
453 {
454   return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
455 }
456
457 /****************************************/
458 /******** CACHE DIR STUFF ***************/
459 /****************************************/
460
461 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
462 #define DIRECTDIRACCESS_WITH_NAME "%s%s" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
463 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
464 #define MAPS_CACHE_DIR maps_layer_default_dir()
465
466 #ifdef WINDOWS
467 #include <io.h>
468 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
469 #define LOCAL_MAPS_DIR "VIKING-MAPS"
470 #elif defined __APPLE__
471 #include <stdlib.h>
472 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
473 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
474 #else /* POSIX */
475 #include <stdlib.h>
476 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
477 #define LOCAL_MAPS_DIR ".viking-maps"
478 #endif
479
480 gchar *maps_layer_default_dir ()
481 {
482   static gchar *defaultdir = NULL;
483   if ( ! defaultdir )
484   {
485     /* Thanks to Mike Davison for the $VIKING_MAPS usage */
486     const gchar *mapdir = g_getenv("VIKING_MAPS");
487     if ( mapdir ) {
488       defaultdir = g_strdup ( mapdir );
489     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
490       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
491     } else {
492       const gchar *home = g_get_home_dir();
493       if (!home || g_access(home, W_OK))
494         home = g_get_home_dir ();
495       if ( home )
496         defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
497       else
498         defaultdir = g_strdup ( LOCAL_MAPS_DIR );
499     }
500     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
501     {
502       /* Add the separator at the end */
503       gchar *tmp = defaultdir;
504       defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
505       g_free(tmp);
506     }
507     g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
508   }
509   return defaultdir;
510 }
511
512 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
513 {
514   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
515   {
516     if ( g_mkdir ( vml->cache_dir, 0777 ) != 0 )
517       g_warning ( "%s: Failed to create directory %s", __FUNCTION__, vml->cache_dir );
518   }
519 }
520
521 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
522 {
523   g_assert ( vml != NULL);
524   g_free ( vml->cache_dir );
525   vml->cache_dir = NULL;
526   const gchar *mydir = dir;
527
528   if ( dir == NULL || dir[0] == '\0' )
529   {
530     if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
531       mydir = a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s;
532   }
533
534   gchar *canonical_dir = vu_get_canonical_filename ( VIK_LAYER(vml), mydir );
535
536   // Ensure cache_dir always ends with a separator
537   guint len = strlen(canonical_dir);
538   // Unless the dir is not valid
539   if ( len > 0 )
540   {
541     if ( canonical_dir[len-1] != G_DIR_SEPARATOR )
542     {
543       vml->cache_dir = g_strconcat ( canonical_dir, G_DIR_SEPARATOR_S, NULL );
544       g_free ( canonical_dir );
545     }
546     else {
547       vml->cache_dir = canonical_dir;
548     }
549
550     maps_layer_mkdir_if_default_dir ( vml );
551   }
552 }
553
554 static void maps_layer_set_file ( VikMapsLayer *vml, const gchar *name )
555 {
556   if ( vml->filename )
557     g_free (vml->filename);
558   vml->filename = g_strdup (name);
559 }
560
561 /****************************************/
562 /******** GOBJECT STUFF *****************/
563 /****************************************/
564
565 GType vik_maps_layer_get_type ()
566 {
567   static GType vml_type = 0;
568
569   if (!vml_type)
570   {
571     static const GTypeInfo vml_info =
572     {
573       sizeof (VikMapsLayerClass),
574       NULL, /* base_init */
575       NULL, /* base_finalize */
576       NULL, /* class init */
577       NULL, /* class_finalize */
578       NULL, /* class_data */
579       sizeof (VikMapsLayer),
580       0,
581       NULL /* instance init */
582     };
583     vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
584   }
585
586   return vml_type;
587 }
588
589 /****************************************/
590 /************** PARAMETERS **************/
591 /****************************************/
592
593 static guint map_index_to_uniq_id (guint16 index)
594 {
595   g_assert ( index < NUM_MAP_TYPES );
596   return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
597 }
598
599 static guint map_uniq_id_to_index ( guint uniq_id )
600 {
601   gint i;
602   for ( i = 0; i < NUM_MAP_TYPES; i++ )
603     if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
604       return i;
605   return NUM_MAP_TYPES; /* no such thing */
606 }
607
608 #define VIK_SETTINGS_MAP_LICENSE_SHOWN "map_license_shown"
609
610 /**
611  * Convenience function to display the license
612  */
613 static void maps_show_license ( GtkWindow *parent, VikMapSource *map )
614 {
615   a_dialog_license ( parent,
616                      vik_map_source_get_label (map),
617                      vik_map_source_get_license (map),
618                      vik_map_source_get_license_url (map) );
619 }
620
621 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
622 {
623   switch ( id )
624   {
625     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
626     case PARAM_CACHE_LAYOUT: if ( data.u < VIK_MAPS_CACHE_LAYOUT_NUM ) vml->cache_layout = data.u; break;
627     case PARAM_FILE: maps_layer_set_file ( vml, data.s ); break;
628     case PARAM_MAPTYPE: {
629       gint maptype = map_uniq_id_to_index(data.u);
630       if ( maptype == NUM_MAP_TYPES )
631         g_warning(_("Unknown map type"));
632       else {
633         vml->maptype = maptype;
634
635         // When loading from a file don't need the license reminder - ensure it's saved into the 'seen' list
636         if ( is_file_operation ) {
637           a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
638         }
639         else {
640           VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
641           if (vik_map_source_get_license (map) != NULL) {
642             // Check if licence for this map type has been shown before
643             if ( ! a_settings_get_integer_list_contains ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u ) ) {
644               if ( vvp )
645                 maps_show_license ( VIK_GTK_WINDOW_FROM_WIDGET(vvp), map );
646               a_settings_set_integer_list_containing ( VIK_SETTINGS_MAP_LICENSE_SHOWN, data.u );
647             }
648           }
649         }
650       }
651       break;
652     }
653     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
654     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
655     case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
656     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
657                           vml->mapzoom_id = data.u;
658                           vml->xmapzoom = __mapzooms_x [data.u];
659                           vml->ymapzoom = __mapzooms_y [data.u];
660                         }else g_warning (_("Unknown Map Zoom")); break;
661     default: break;
662   }
663   return TRUE;
664 }
665
666 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
667 {
668   VikLayerParamData rv;
669   switch ( id )
670   {
671     case PARAM_CACHE_DIR:
672     {
673       gboolean set = FALSE;
674       /* Only save a blank when the map cache location equals the default
675           On reading in, when it is blank then the default is reconstructed
676           Since the default changes dependent on the user and OS, it means the resultant file is more portable */
677       if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 ) {
678         rv.s = "";
679         set = TRUE;
680       }
681       else if ( is_file_operation && vml->cache_dir ) {
682         if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) {
683           gchar *cwd = g_get_current_dir();
684           if ( cwd ) {
685             rv.s = file_GetRelativeFilename ( cwd, vml->cache_dir );
686             if ( !rv.s ) rv.s = "";
687             set = TRUE;
688           }
689         }
690       }
691       if ( !set )
692         rv.s = vml->cache_dir ? vml->cache_dir : "";
693       break;
694     }
695     case PARAM_CACHE_LAYOUT: rv.u = vml->cache_layout; break;
696     case PARAM_FILE: rv.s = vml->filename; break;
697     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
698     case PARAM_ALPHA: rv.u = vml->alpha; break;
699     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
700     case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
701     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
702     default: break;
703   }
704   return rv;
705 }
706
707 static void maps_layer_change_param ( GtkWidget *widget, ui_change_values values )
708 {
709   switch ( GPOINTER_TO_INT(values[UI_CHG_PARAM_ID]) ) {
710     // Alter sensitivity of download option widgets according to the maptype setting.
711     case PARAM_MAPTYPE: {
712       // Get new value
713       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
714       // Is it *not* the OSM On Disk Tile Layout or the MBTiles type or the OSM Metatiles type
715       gboolean sensitive = ( MAP_ID_OSM_ON_DISK != vlpd.u &&
716                              MAP_ID_MBTILES != vlpd.u &&
717                              MAP_ID_OSM_METATILES != vlpd.u );
718       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
719       GtkWidget **ww2 = values[UI_CHG_LABELS];
720       GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
721       GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
722       GtkWidget *w3 = ww1[PARAM_AUTODOWNLOAD];
723       GtkWidget *w4 = ww2[PARAM_AUTODOWNLOAD];
724       // Depends on autodownload value
725       gboolean missing_sense = sensitive && VIK_MAPS_LAYER(values[UI_CHG_LAYER])->autodownload;
726       if ( w1 ) gtk_widget_set_sensitive ( w1, missing_sense );
727       if ( w2 ) gtk_widget_set_sensitive ( w2, missing_sense );
728       if ( w3 ) gtk_widget_set_sensitive ( w3, sensitive );
729       if ( w4 ) gtk_widget_set_sensitive ( w4, sensitive );
730
731       // Cache type not applicable either
732       GtkWidget *w9 = ww1[PARAM_CACHE_LAYOUT];
733       GtkWidget *w10 = ww2[PARAM_CACHE_LAYOUT];
734       if ( w9 ) gtk_widget_set_sensitive ( w9, sensitive );
735       if ( w10 ) gtk_widget_set_sensitive ( w10, sensitive );
736
737       // File only applicable for MBTiles type
738       // Directory for all other types
739       sensitive = ( MAP_ID_MBTILES == vlpd.u);
740       GtkWidget *w5 = ww1[PARAM_FILE];
741       GtkWidget *w6 = ww2[PARAM_FILE];
742       GtkWidget *w7 = ww1[PARAM_CACHE_DIR];
743       GtkWidget *w8 = ww2[PARAM_CACHE_DIR];
744       if ( w5 ) gtk_widget_set_sensitive ( w5, sensitive );
745       if ( w6 ) gtk_widget_set_sensitive ( w6, sensitive );
746       if ( w7 ) gtk_widget_set_sensitive ( w7, !sensitive );
747       if ( w8 ) gtk_widget_set_sensitive ( w8, !sensitive );
748
749       break;
750     }
751
752     // Alter sensitivity of 'download only missing' widgets according to the autodownload setting.
753     case PARAM_AUTODOWNLOAD: {
754       // Get new value
755       VikLayerParamData vlpd = a_uibuilder_widget_get_value ( widget, values[UI_CHG_PARAM] );
756       GtkWidget **ww1 = values[UI_CHG_WIDGETS];
757       GtkWidget **ww2 = values[UI_CHG_LABELS];
758       GtkWidget *w1 = ww1[PARAM_ONLYMISSING];
759       GtkWidget *w2 = ww2[PARAM_ONLYMISSING];
760       if ( w1 ) gtk_widget_set_sensitive ( w1, vlpd.b );
761       if ( w2 ) gtk_widget_set_sensitive ( w2, vlpd.b );
762       break;
763     }
764     default: break;
765   }
766 }
767
768 /****************************************/
769 /****** CREATING, COPYING, FREEING ******/
770 /****************************************/
771
772 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
773 {
774   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
775   vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
776
777   vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
778
779   vml->dl_tool_x = vml->dl_tool_y = -1;
780   vml->last_center = NULL;
781   vml->last_xmpp = 0.0;
782   vml->last_ympp = 0.0;
783
784   vml->dl_right_click_menu = NULL;
785   vml->filename = NULL;
786   return vml;
787 }
788
789 static void maps_layer_free ( VikMapsLayer *vml )
790 {
791   g_free ( vml->cache_dir );
792   vml->cache_dir = NULL;
793   if ( vml->dl_right_click_menu )
794     g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
795   g_free(vml->last_center);
796   vml->last_center = NULL;
797   g_free ( vml->filename );
798   vml->filename = NULL;
799
800 #ifdef HAVE_SQLITE3_H
801   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
802   if ( vik_map_source_is_mbtiles ( map ) ) {
803     if ( vml->mbtiles ) {
804       int ans = sqlite3_close ( vml->mbtiles );
805       if ( ans != SQLITE_OK ) {
806         // Only to console for information purposes only
807         g_warning ( "SQL Close problem: %d", ans );
808       }
809     }
810   }
811 #endif
812 }
813
814 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
815 {
816   VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
817   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
818
819   if (!from_file)
820   {
821     /* If this method is not called in file reading context
822      * it is called in GUI context.
823      * So, we can check if we have to inform the user about inconsistency */
824     VikViewportDrawMode vp_drawmode;
825     vp_drawmode = vik_viewport_get_drawmode ( vp );
826
827     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
828       const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
829       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
830       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
831       g_free(msg);
832     }
833   }
834   
835   // Performed in post read as we now know the map type
836 #ifdef HAVE_SQLITE3_H
837   // Do some SQL stuff
838   if ( vik_map_source_is_mbtiles ( map ) ) {
839     int ans = sqlite3_open_v2 ( vml->filename,
840                                 &(vml->mbtiles),
841                                 SQLITE_OPEN_READONLY,
842                                 NULL );
843     if ( ans != SQLITE_OK ) {
844       // That didn't work, so here's why:
845       g_warning ( "%s: %s", __FUNCTION__, sqlite3_errmsg ( vml->mbtiles ) );
846
847       a_dialog_error_msg_extra ( VIK_GTK_WINDOW_FROM_WIDGET(vp),
848                                  _("Failed to open MBTiles file: %s"),
849                                  vml->filename );
850       vml->mbtiles = NULL;
851     }
852   }
853 #endif
854
855   // If the on Disk OSM Tile Layout type
856   if ( vik_map_source_get_uniq_id(map) == MAP_ID_OSM_ON_DISK ) {
857     // Copy the directory into filename
858     //  thus the mapcache look up will be unique when using more than one of these map types
859     g_free ( vml->filename );
860     vml->filename = g_strdup (vml->cache_dir);
861   }
862 }
863
864 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
865 {
866   return vik_maps_layer_get_map_label ( vml );
867 }
868
869 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
870 {
871   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
872 }
873
874 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
875 {
876   VikMapsLayer *rv = maps_layer_new ( vvp );
877   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
878   maps_layer_post_read ( VIK_LAYER(rv), vvp, FALSE );
879   return rv;
880 }
881
882 /*********************/
883 /****** DRAWING ******/
884 /*********************/
885
886 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
887 {
888   GdkPixbuf *tmp;
889   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
890   tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
891   g_object_unref ( G_OBJECT(pixbuf) );
892   return tmp;
893 }
894
895 #ifdef HAVE_SQLITE3_H
896 /*
897 static int sql_select_tile_dump_cb (void *data, int cols, char **fields, char **col_names )
898 {
899   g_warning ( "Found %d columns", cols );
900   int i;
901   for ( i = 0; i < cols; i++ ) {
902     g_warning ( "SQL processing %s = %s", col_names[i], fields[i] );
903   }
904   return 0;
905 }
906 */
907
908 /**
909  *
910  */
911 static GdkPixbuf *get_pixbuf_sql_exec ( sqlite3 *sql, gint xx, gint yy, gint zoom )
912 {
913   GdkPixbuf *pixbuf = NULL;
914
915   // MBTiles stored internally with the flipping y thingy (i.e. TMS scheme).
916   gint flip_y = (gint) pow(2, zoom)-1 - yy;
917   gchar *statement = g_strdup_printf ( "SELECT tile_data FROM tiles WHERE zoom_level=%d AND tile_column=%d AND tile_row=%d;", zoom, xx, flip_y );
918
919   gboolean finished = FALSE;
920
921   sqlite3_stmt *sql_stmt = NULL;
922   int ans = sqlite3_prepare_v2 ( sql, statement, -1, &sql_stmt, NULL );
923   if ( ans != SQLITE_OK ) {
924     g_warning ( "%s: %s - %d: %s", __FUNCTION__, "prepare failure", ans, statement );
925     finished = TRUE;
926   }
927
928   while ( !finished ) {
929     ans = sqlite3_step ( sql_stmt );
930     switch (ans) {
931       case SQLITE_ROW: {
932         // Get tile_data blob
933         int count = sqlite3_column_count(sql_stmt);
934         if ( count != 1 )  {
935           g_warning ( "%s: %s - %d", __FUNCTION__, "count not one", count );
936           finished = TRUE;
937         }
938         else {
939           const void *data = sqlite3_column_blob ( sql_stmt, 0 );
940           int bytes = sqlite3_column_bytes ( sql_stmt, 0 );
941           if ( bytes < 1 )  {
942             g_warning ( "%s: %s (%d)", __FUNCTION__, "not enough bytes", bytes );
943             finished = TRUE;
944           }
945           else {
946             // Convert these blob bytes into a pixbuf via these streaming operations
947             GInputStream *stream = g_memory_input_stream_new_from_data ( data, bytes, NULL );
948             GError *error = NULL;
949             pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
950             if ( error ) {
951               g_warning ( "%s: %s", __FUNCTION__, error->message );
952               g_error_free ( error );
953             }
954             g_input_stream_close ( stream, NULL, NULL );
955           }
956         }
957         break;
958       }
959       default:
960        // e.g. SQLITE_DONE | SQLITE_ERROR | SQLITE_MISUSE | etc...
961        // Finished normally
962        //  and give up on any errors
963        if ( ans != SQLITE_DONE )
964          g_warning ( "%s: %s - %d", __FUNCTION__, "step issue", ans );
965        finished = TRUE;
966        break;
967     }
968   }
969   (void)sqlite3_finalize ( sql_stmt );
970   
971   g_free ( statement );
972
973   return pixbuf;
974 }
975 #endif
976
977 static GdkPixbuf *get_mbtiles_pixbuf ( VikMapsLayer *vml, gint xx, gint yy, gint zoom )
978 {
979   GdkPixbuf *pixbuf = NULL;
980
981 #ifdef HAVE_SQLITE3_H
982   if ( vml->mbtiles ) {
983     /*
984     gchar *statement = g_strdup_printf ( "SELECT name FROM sqlite_master WHERE type='table';" );
985     char *errMsg = NULL;
986     int ans = sqlite3_exec ( vml->mbtiles, statement, sql_select_tile_dump_cb, pixbuf, &errMsg );
987     if ( ans != SQLITE_OK ) {
988       // Only to console for information purposes only
989       g_warning ( "SQL problem: %d for %s - error: %s", ans, statement, errMsg );
990       sqlite3_free( errMsg );
991     }
992     g_free ( statement );
993     */
994
995     // Reading BLOBS is a bit more involved and so can't use the simpler sqlite3_exec ()
996     // Hence this specific function
997     pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, xx, yy, zoom );
998   }
999 #endif
1000
1001   return pixbuf;
1002 }
1003
1004 static GdkPixbuf *get_pixbuf_from_metatile ( VikMapsLayer *vml, gint xx, gint yy, gint zz )
1005 {
1006   const int tile_max = METATILE_MAX_SIZE;
1007   char err_msg[PATH_MAX];
1008   char *buf;
1009   int len;
1010   int compressed;
1011
1012   buf = g_malloc(tile_max);
1013   if (!buf) {
1014       return NULL;
1015   }
1016
1017   err_msg[0] = 0;
1018   len = metatile_read(vml->cache_dir, xx, yy, zz, buf, tile_max, &compressed, err_msg);
1019
1020   if (len > 0) {
1021     if (compressed) {
1022       // Not handled yet - I don't think this is used often - so implement later if necessary
1023       g_warning ( "Compressed metatiles not implemented:%s\n", __FUNCTION__);
1024       g_free(buf);
1025       return NULL;
1026     }
1027
1028     // Convert these buf bytes into a pixbuf via these streaming operations
1029     GdkPixbuf *pixbuf = NULL;
1030
1031     GInputStream *stream = g_memory_input_stream_new_from_data ( buf, len, NULL );
1032     GError *error = NULL;
1033     pixbuf = gdk_pixbuf_new_from_stream ( stream, NULL, &error );
1034     if (error) {
1035       g_warning ( "%s: %s", __FUNCTION__, error->message );
1036       g_error_free ( error );
1037     }
1038     g_input_stream_close ( stream, NULL, NULL );
1039
1040     g_free(buf);
1041     return pixbuf;
1042   }
1043   else {
1044     g_free(buf);
1045     g_warning ( "FAILED:%s %s", __FUNCTION__, err_msg);
1046     return NULL;
1047   }
1048 }
1049
1050 /**
1051  * Caller has to decrease reference counter of returned
1052  * GdkPixbuf, when buffer is no longer needed.
1053  */
1054 static GdkPixbuf *pixbuf_apply_settings ( GdkPixbuf *pixbuf, VikMapsLayer *vml, MapCoord *mapcoord, gdouble xshrinkfactor, gdouble yshrinkfactor )
1055 {
1056   // Apply alpha setting
1057   if ( pixbuf && vml->alpha < 255 )
1058     pixbuf = ui_pixbuf_set_alpha ( pixbuf, vml->alpha );
1059
1060   if ( pixbuf && ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 ) )
1061     pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
1062
1063   if ( pixbuf )
1064     a_mapcache_add ( pixbuf, (mapcache_extra_t) {0.0}, mapcoord->x, mapcoord->y,
1065                      mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
1066                      mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1067
1068   return pixbuf;
1069 }
1070
1071 static void get_filename ( const gchar *cache_dir,
1072                            VikMapsCacheLayout cl,
1073                            guint16 id,
1074                            const gchar *name,
1075                            gint scale,
1076                            gint z,
1077                            gint x,
1078                            gint y,
1079                            gchar *filename_buf,
1080                            gint buf_len,
1081                            const gchar* file_extension )
1082 {
1083   switch ( cl ) {
1084     case VIK_MAPS_CACHE_LAYOUT_OSM:
1085       if ( name ) {
1086         if ( g_strcmp0 ( cache_dir, MAPS_CACHE_DIR ) )
1087           // Cache dir not the default - assume it's been directed somewhere specific
1088           g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1089         else
1090           // Using default cache - so use the map name in the directory path
1091           g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS_WITH_NAME, cache_dir, name, (17 - scale), x, y, file_extension );
1092       }
1093       else
1094         g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS, cache_dir, (17 - scale), x, y, file_extension );
1095       break;
1096     default:
1097       g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE, cache_dir, id, scale, z, x, y );
1098       break;
1099   }
1100 }
1101
1102 /**
1103  * Caller has to decrease reference counter of returned
1104  * GdkPixbuf, when buffer is no longer needed.
1105  */
1106 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, guint16 id, const gchar* mapname, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
1107 {
1108   GdkPixbuf *pixbuf;
1109
1110   /* get the thing */
1111   pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
1112                             id, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor, vml->filename );
1113
1114   if ( ! pixbuf ) {
1115     VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1116     if ( vik_map_source_is_direct_file_access(map) ) {
1117       // ATM MBTiles must be 'a direct access type'
1118       if ( vik_map_source_is_mbtiles(map) ) {
1119         pixbuf = get_mbtiles_pixbuf ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1120         pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1121         // return now to avoid file tests that aren't appropriate for this map type
1122         return pixbuf;
1123       }
1124       else if ( vik_map_source_is_osm_meta_tiles(map) ) {
1125         pixbuf = get_pixbuf_from_metatile ( vml, mapcoord->x, mapcoord->y, (17 - mapcoord->scale) );
1126         pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1127         return pixbuf;
1128       }
1129       else
1130         get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, NULL,
1131                        mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1132                        vik_map_source_get_file_extension(map) );
1133     }
1134     else
1135       get_filename ( vml->cache_dir, vml->cache_layout, id, mapname,
1136                      mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y, filename_buf, buf_len,
1137                      vik_map_source_get_file_extension(map) );
1138
1139     if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1140     {
1141       GError *gx = NULL;
1142       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
1143
1144       /* free the pixbuf on error */
1145       if (gx)
1146       {
1147         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE ) {
1148           // Report a warning
1149           if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1150             gchar* msg = g_strdup_printf ( _("Couldn't open image file: %s"), gx->message );
1151             vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1152             g_free (msg);
1153           }
1154         }
1155
1156         g_error_free ( gx );
1157         if ( pixbuf )
1158           g_object_unref ( G_OBJECT(pixbuf) );
1159         pixbuf = NULL;
1160       } else {
1161         pixbuf = pixbuf_apply_settings ( pixbuf, vml, mapcoord, xshrinkfactor, yshrinkfactor );
1162       }
1163     }
1164   }
1165   return pixbuf;
1166 }
1167
1168 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
1169 {
1170   const VikCoord *center = vik_viewport_get_center ( vvp );
1171
1172   if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
1173     /* D'n'D pan in action: do not download */
1174     return FALSE;
1175
1176   // Don't attempt to download unsupported zoom levels
1177   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1178   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1179   guint8 zl = map_utils_mpp_to_zoom_level ( xzoom );
1180   if ( zl < vik_map_source_get_zoom_min(map) || zl > vik_map_source_get_zoom_max(map) )
1181     return FALSE;
1182
1183   if (vml->last_center == NULL) {
1184     VikCoord *new_center = g_malloc(sizeof(VikCoord));
1185     *new_center = *center;
1186     vml->last_center = new_center;
1187     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1188     vml->last_ympp = vik_viewport_get_ympp(vvp);
1189     return TRUE;
1190   }
1191
1192   /* TODO: perhaps vik_coord_diff() */
1193   if (vik_coord_equals(vml->last_center, center)
1194       && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
1195       && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
1196     return FALSE;
1197
1198   *(vml->last_center) = *center;
1199     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
1200     vml->last_ympp = vik_viewport_get_ympp(vvp);
1201   return TRUE;
1202 }
1203
1204 /**
1205  *
1206  */
1207 gboolean try_draw_scale_down (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1208                               gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1209 {
1210   GdkPixbuf *pixbuf;
1211   int scale_inc;
1212   for (scale_inc = 1; scale_inc <= SCALE_INC_DOWN; scale_inc++) {
1213     // Try with smaller zooms
1214     int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
1215     MapCoord ulm2 = ulm;
1216     ulm2.x = ulm.x / scale_factor;
1217     ulm2.y = ulm.y / scale_factor;
1218     ulm2.scale = ulm.scale + scale_inc;
1219     pixbuf = get_pixbuf ( vml, id, mapname, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1220     if ( pixbuf ) {
1221       gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1222       gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1223       vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1224       g_object_unref(pixbuf);
1225       return TRUE;
1226     }
1227   }
1228   return FALSE;
1229 }
1230
1231 /**
1232  *
1233  */
1234 gboolean try_draw_scale_up (VikMapsLayer *vml, VikViewport *vvp, MapCoord ulm, gint xx, gint yy, gint tilesize_x_ceil, gint tilesize_y_ceil,
1235                             gdouble xshrinkfactor, gdouble yshrinkfactor, guint id, const gchar *mapname, gchar *path_buf, guint max_path_len)
1236 {
1237   GdkPixbuf *pixbuf;
1238   // Try with bigger zooms
1239   int scale_dec;
1240   for (scale_dec = 1; scale_dec <= SCALE_INC_UP; scale_dec++) {
1241     int pict_x, pict_y;
1242     int scale_factor = 1 << scale_dec;  /*  2^scale_dec */
1243     MapCoord ulm2 = ulm;
1244     ulm2.x = ulm.x * scale_factor;
1245     ulm2.y = ulm.y * scale_factor;
1246     ulm2.scale = ulm.scale - scale_dec;
1247     for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
1248       for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
1249         MapCoord ulm3 = ulm2;
1250         ulm3.x += pict_x;
1251         ulm3.y += pict_y;
1252         pixbuf = get_pixbuf ( vml, id, mapname, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
1253         if ( pixbuf ) {
1254           gint src_x = 0;
1255           gint src_y = 0;
1256           gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
1257           gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
1258           vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
1259           g_object_unref(pixbuf);
1260           return TRUE;
1261         }
1262       }
1263     }
1264   }
1265   return FALSE;
1266 }
1267
1268 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
1269 {
1270   MapCoord ulm, brm;
1271   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
1272   gdouble yzoom = vik_viewport_get_ympp ( vvp );
1273   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
1274   gboolean existence_only = FALSE;
1275
1276   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
1277     xshrinkfactor = vml->xmapzoom / xzoom;
1278     yshrinkfactor = vml->ymapzoom / yzoom;
1279     xzoom = vml->xmapzoom;
1280     yzoom = vml->xmapzoom;
1281     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
1282          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
1283       if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
1284         g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
1285         existence_only = TRUE;
1286       }
1287       else {
1288         // Report the reason for not drawing
1289         if ( IS_VIK_WINDOW ((VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml)) ) {
1290           gchar* msg = g_strdup_printf ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
1291           vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vml), msg, VIK_STATUSBAR_INFO );
1292           g_free (msg);
1293         }
1294         return;
1295       }
1296     }
1297   }
1298
1299   /* coord -> ID */
1300   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1301   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
1302        vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
1303
1304     /* loop & draw */
1305     gint x, y;
1306     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
1307     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
1308     guint16 id = vik_map_source_get_uniq_id(map);
1309     const gchar *mapname = vik_map_source_get_name(map);
1310
1311     VikCoord coord;
1312     gint xx, yy, width, height;
1313     GdkPixbuf *pixbuf;
1314
1315     // Prevent the program grinding to a halt if trying to deal with thousands of tiles
1316     //  which can happen when using a small fixed zoom level and viewing large areas.
1317     // Also prevents very large number of tile download requests
1318     gint tiles = (xmax-xmin) * (ymax-ymin);
1319     if ( tiles > MAX_TILES ) {
1320       g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
1321       existence_only = TRUE;
1322     }
1323
1324     guint max_path_len = strlen(vml->cache_dir) + 40;
1325     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
1326
1327     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
1328       g_debug("%s: Starting autodownload", __FUNCTION__);
1329       if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
1330         // Try to download newer tiles
1331         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
1332       else
1333         // Download only missing tiles
1334         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
1335     }
1336
1337     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
1338       for ( x = xmin; x <= xmax; x++ ) {
1339         for ( y = ymin; y <= ymax; y++ ) {
1340           ulm.x = x;
1341           ulm.y = y;
1342           pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
1343           if ( pixbuf ) {
1344             width = gdk_pixbuf_get_width ( pixbuf );
1345             height = gdk_pixbuf_get_height ( pixbuf );
1346
1347             vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1348             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
1349             xx -= (width/2);
1350             yy -= (height/2);
1351
1352             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
1353             g_object_unref(pixbuf);
1354           }
1355         }
1356       }
1357     } else { /* tilesize is known, don't have to keep converting coords */
1358       gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
1359       gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
1360       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
1361       gint tilesize_x_ceil = ceil ( tilesize_x );
1362       gint tilesize_y_ceil = ceil ( tilesize_y );
1363       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
1364       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
1365       gint xx_tmp, yy_tmp;
1366       gint base_yy, xend, yend;
1367
1368       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
1369       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
1370
1371       vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
1372       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
1373       xx = xx_tmp; yy = yy_tmp;
1374       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
1375        * eg if tile size 128, shrinkfactor 0.333 */
1376       xx -= (tilesize_x/2);
1377       base_yy = yy - (tilesize_y/2);
1378
1379       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1380         yy = base_yy;
1381         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1382           ulm.x = x;
1383           ulm.y = y;
1384
1385           if ( existence_only ) {
1386             if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
1387               get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM, id, vik_map_source_get_name(map),
1388                              ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1389             else
1390               get_filename ( vml->cache_dir, vml->cache_layout, id, vik_map_source_get_name(map),
1391                              ulm.scale, ulm.z, ulm.x, ulm.y, path_buf, max_path_len, vik_map_source_get_file_extension(map) );
1392
1393             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
1394               GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
1395               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
1396             }
1397           } else {
1398             // Try correct scale first
1399             int scale_factor = 1;
1400             pixbuf = get_pixbuf ( vml, id, mapname, &ulm, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
1401             if ( pixbuf ) {
1402               gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
1403               gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
1404               vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
1405               g_object_unref(pixbuf);
1406             }
1407             else {
1408               // Otherwise try different scales
1409               if ( SCALE_SMALLER_ZOOM_FIRST ) {
1410                 if ( !try_draw_scale_down(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len) ) {
1411                   try_draw_scale_up(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len);
1412                 }
1413               }
1414               else {
1415                 if ( !try_draw_scale_up(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len) ) {
1416                   try_draw_scale_down(vml,vvp,ulm,xx,yy,tilesize_x_ceil,tilesize_y_ceil,xshrinkfactor,yshrinkfactor,id,mapname,path_buf,max_path_len);
1417                 }
1418               }
1419             }
1420           }
1421
1422           yy += tilesize_y;
1423         }
1424         xx += tilesize_x;
1425       }
1426
1427       // ATM Only show tile grid lines in extreme debug mode
1428       if ( vik_debug && vik_verbose ) {
1429         /* Grid drawing here so it gets drawn on top of the map */
1430         /* Thus loop around x & y again, but this time separately */
1431         /* Only showing grid for the current scale */
1432         GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
1433         /* Draw single grid lines across the whole screen */
1434         gint width = vik_viewport_get_width(vvp);
1435         gint height = vik_viewport_get_height(vvp);
1436         xx = xx_tmp; yy = yy_tmp;
1437         gint base_xx = xx - (tilesize_x/2);
1438         base_yy = yy - (tilesize_y/2);
1439
1440         xx = base_xx;
1441         for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
1442           vik_viewport_draw_line ( vvp, black_gc, xx, base_yy, xx, height );
1443           xx += tilesize_x;
1444         }
1445
1446         yy = base_yy;
1447         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
1448           vik_viewport_draw_line ( vvp, black_gc, base_xx, yy, width, yy );
1449           yy += tilesize_y;
1450         }
1451       }
1452
1453     }
1454     g_free ( path_buf );
1455   }
1456 }
1457
1458 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
1459 {
1460   if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
1461   {
1462     VikCoord ul, br;
1463
1464     /* Copyright */
1465     gdouble level = vik_viewport_get_zoom ( vvp );
1466     LatLonBBox bbox;
1467     vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
1468     vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
1469
1470     /* Logo */
1471     const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
1472     vik_viewport_add_logo ( vvp, logo );
1473
1474     /* get corner coords */
1475     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
1476       /* UTM multi-zone stuff by Kit Transue */
1477       gchar leftmost_zone, rightmost_zone, i;
1478       leftmost_zone = vik_viewport_leftmost_zone( vvp );
1479       rightmost_zone = vik_viewport_rightmost_zone( vvp );
1480       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
1481         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
1482         maps_layer_draw_section ( vml, vvp, &ul, &br );
1483       }
1484     }
1485     else {
1486       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1487       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1488
1489       maps_layer_draw_section ( vml, vvp, &ul, &br );
1490     }
1491   }
1492 }
1493
1494 /*************************/
1495 /****** DOWNLOADING ******/
1496 /*************************/
1497
1498 /* pass along data to thread, exists even if layer is deleted. */
1499 typedef struct {
1500   gchar *cache_dir;
1501   gchar *filename_buf;
1502   VikMapsCacheLayout cache_layout;
1503   gint x0, y0, xf, yf;
1504   MapCoord mapcoord;
1505   gint maptype;
1506   gint maxlen;
1507   gint mapstoget;
1508   gint redownload;
1509   gboolean refresh_display;
1510   VikMapsLayer *vml;
1511   VikViewport *vvp;
1512   gboolean map_layer_alive;
1513   GMutex *mutex;
1514 } MapDownloadInfo;
1515
1516 static void mdi_free ( MapDownloadInfo *mdi )
1517 {
1518   vik_mutex_free(mdi->mutex);
1519   g_free ( mdi->cache_dir );
1520   mdi->cache_dir = NULL;
1521   g_free ( mdi->filename_buf );
1522   mdi->filename_buf = NULL;
1523   g_free ( mdi );
1524 }
1525
1526 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
1527 {
1528   MapDownloadInfo *mdi = ptr;
1529   g_mutex_lock(mdi->mutex);
1530   mdi->map_layer_alive = FALSE;
1531   g_mutex_unlock(mdi->mutex);
1532 }
1533
1534 static gboolean is_in_area (VikMapSource *map, MapCoord mc)
1535 {
1536   VikCoord vc;
1537   vik_map_source_mapcoord_to_center_coord ( map, &mc, &vc );
1538
1539   struct LatLon tl;
1540   tl.lat = vik_map_source_get_lat_max(map);
1541   tl.lon = vik_map_source_get_lon_min(map);
1542   struct LatLon br;
1543   br.lat = vik_map_source_get_lat_min(map);
1544   br.lon = vik_map_source_get_lon_max(map);
1545   VikCoord vctl;
1546   vik_coord_load_from_latlon (&vctl, VIK_COORD_LATLON, &tl);
1547   VikCoord vcbr;
1548   vik_coord_load_from_latlon (&vcbr, VIK_COORD_LATLON, &br);
1549
1550   return vik_coord_inside ( &vc, &vctl, &vcbr );
1551 }
1552
1553 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
1554 {
1555   void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1556   guint donemaps = 0;
1557   MapCoord mcoord = mdi->mapcoord;
1558   gint x, y;
1559   for ( x = mdi->x0; x <= mdi->xf; x++ )
1560   {
1561     mcoord.x = x;
1562     for ( y = mdi->y0; y <= mdi->yf; y++ )
1563     {
1564       mcoord.y = y;
1565       // Only attempt to download a tile from supported areas
1566       if ( is_in_area ( MAPS_LAYER_NTH_TYPE(mdi->maptype), mcoord ) )
1567       {
1568         gboolean remove_mem_cache = FALSE;
1569         gboolean need_download = FALSE;
1570
1571         get_filename ( mdi->cache_dir, mdi->cache_layout,
1572                        vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1573                        vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1574                        mdi->mapcoord.scale, mdi->mapcoord.z, x, y, mdi->filename_buf, mdi->maxlen,
1575                        vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1576
1577         donemaps++;
1578         int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1579         if (res != 0) {
1580           vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1581           return -1;
1582         }
1583
1584         if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1585           need_download = TRUE;
1586           remove_mem_cache = TRUE;
1587
1588         } else {  /* in case map file already exists */
1589           switch (mdi->redownload) {
1590             case REDOWNLOAD_NONE:
1591               continue;
1592
1593             case REDOWNLOAD_BAD:
1594             {
1595               /* see if this one is bad or what */
1596               GError *gx = NULL;
1597               GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1598               if (gx || (!pixbuf)) {
1599                 if ( g_remove ( mdi->filename_buf ) )
1600                   g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
1601                 need_download = TRUE;
1602                 remove_mem_cache = TRUE;
1603                 g_error_free ( gx );
1604
1605               } else {
1606                 g_object_unref ( pixbuf );
1607               }
1608               break;
1609             }
1610
1611             case REDOWNLOAD_NEW:
1612               need_download = TRUE;
1613               remove_mem_cache = TRUE;
1614               break;
1615
1616             case REDOWNLOAD_ALL:
1617               /* FIXME: need a better way than to erase file in case of server/network problem */
1618               if ( g_remove ( mdi->filename_buf ) )
1619                 g_warning ( "REDOWNLOAD failed to remove: %s", mdi->filename_buf );
1620               need_download = TRUE;
1621               remove_mem_cache = TRUE;
1622               break;
1623
1624             case DOWNLOAD_OR_REFRESH:
1625               remove_mem_cache = TRUE;
1626               break;
1627
1628             default:
1629               g_warning ( "redownload state %d unknown\n", mdi->redownload);
1630           }
1631         }
1632
1633         mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1634
1635         if (need_download) {
1636           DownloadResult_t dr = vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle);
1637           switch ( dr ) {
1638             case DOWNLOAD_PARAMETERS_ERROR:
1639             case DOWNLOAD_HTTP_ERROR:
1640             case DOWNLOAD_CONTENT_ERROR: {
1641               // TODO: ?? count up the number of download errors somehow...
1642               gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Failed to download tile") );
1643               vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1644               g_free (msg);
1645               break;
1646             }
1647             case DOWNLOAD_FILE_WRITE_ERROR: {
1648               gchar* msg = g_strdup_printf ( "%s: %s", vik_maps_layer_get_map_label (mdi->vml), _("Unable to save tile") );
1649               vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(mdi->vml), msg, VIK_STATUSBAR_INFO );
1650               g_free (msg);
1651               break;
1652             }
1653             case DOWNLOAD_SUCCESS:
1654             case DOWNLOAD_NOT_REQUIRED:
1655             default:
1656               break;
1657           }
1658         }
1659
1660         g_mutex_lock(mdi->mutex);
1661         if (remove_mem_cache)
1662             a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)), mdi->mapcoord.scale, mdi->vml->filename );
1663         if (mdi->refresh_display && mdi->map_layer_alive) {
1664           /* TODO: check if it's on visible area */
1665           vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1666         }
1667         g_mutex_unlock(mdi->mutex);
1668         mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1669       }
1670     }
1671   }
1672   vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1673   g_mutex_lock(mdi->mutex);
1674   if (mdi->map_layer_alive)
1675     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1676   g_mutex_unlock(mdi->mutex); 
1677   return 0;
1678 }
1679
1680 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1681 {
1682   if ( mdi->mapcoord.x || mdi->mapcoord.y )
1683   {
1684     get_filename ( mdi->cache_dir, mdi->cache_layout,
1685                    vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1686                    vik_map_source_get_name(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1687                    mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y, mdi->filename_buf, mdi->maxlen,
1688                    vik_map_source_get_file_extension(MAPS_LAYER_NTH_TYPE(mdi->maptype)) );
1689     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1690     {
1691       if ( g_remove ( mdi->filename_buf ) )
1692         g_warning ( "Cleanup failed to remove: %s", mdi->filename_buf );
1693     }
1694   }
1695 }
1696
1697 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1698 {
1699   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1700   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1701   MapCoord ulm, brm;
1702   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1703
1704   // Don't ever attempt download on direct access
1705   if ( vik_map_source_is_direct_file_access ( map ) )
1706     return;
1707
1708   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
1709     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1710   {
1711     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1712     gint a, b;
1713
1714     mdi->vml = vml;
1715     mdi->vvp = vvp;
1716     mdi->map_layer_alive = TRUE;
1717     mdi->mutex = vik_mutex_new();
1718     mdi->refresh_display = TRUE;
1719
1720     /* cache_dir and buffer for dest filename */
1721     mdi->cache_dir = g_strdup ( vml->cache_dir );
1722     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1723     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1724     mdi->cache_layout = vml->cache_layout;
1725     mdi->maptype = vml->maptype;
1726
1727     mdi->mapcoord = ulm;
1728     mdi->redownload = redownload;
1729
1730     mdi->x0 = MIN(ulm.x, brm.x);
1731     mdi->xf = MAX(ulm.x, brm.x);
1732     mdi->y0 = MIN(ulm.y, brm.y);
1733     mdi->yf = MAX(ulm.y, brm.y);
1734
1735     mdi->mapstoget = 0;
1736
1737     MapCoord mcoord = mdi->mapcoord;
1738
1739     if ( mdi->redownload ) {
1740       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1741     } else {
1742       /* calculate how many we need */
1743       for ( a = mdi->x0; a <= mdi->xf; a++ )
1744       {
1745         mcoord.x = a;
1746         for ( b = mdi->y0; b <= mdi->yf; b++ )
1747         {
1748           mcoord.y = b;
1749           // Only count tiles from supported areas
1750           if ( is_in_area (map, mcoord) )
1751           {
1752             get_filename ( mdi->cache_dir, mdi->cache_layout,
1753                            vik_map_source_get_uniq_id(map),
1754                            vik_map_source_get_name(map),
1755                            ulm.scale, ulm.z, a, b, mdi->filename_buf, mdi->maxlen,
1756                            vik_map_source_get_file_extension(map) );
1757             if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1758               mdi->mapstoget++;
1759           }
1760         }
1761       }
1762     }
1763
1764     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1765
1766     if ( mdi->mapstoget )
1767     {
1768       const gchar *tmp_str;
1769       gchar *tmp;
1770
1771       if (redownload) 
1772       {
1773         if (redownload == REDOWNLOAD_BAD)
1774           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1775         else
1776           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1777       } 
1778       else 
1779       {
1780         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1781       }
1782       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1783  
1784       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1785       /* launch the thread */
1786       a_background_thread ( BACKGROUND_POOL_REMOTE,
1787                             VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1788                             tmp,                                              /* description string */
1789                             (vik_thr_func) map_download_thread,               /* function to call within thread */
1790                             mdi,                                              /* pass along data */
1791                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
1792                             (vik_thr_free_func) mdi_cancel_cleanup,
1793                             mdi->mapstoget );
1794       g_free ( tmp );
1795     }
1796     else
1797       mdi_free ( mdi );
1798   }
1799 }
1800
1801 static void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint download_method )
1802 {
1803   MapCoord ulm, brm;
1804   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1805
1806   // Don't ever attempt download on direct access
1807   if ( vik_map_source_is_direct_file_access ( map ) )
1808     return;
1809
1810   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
1811     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1812     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1813     return;
1814   }
1815
1816   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1817   gint i, j;
1818
1819   mdi->vml = vml;
1820   mdi->vvp = vvp;
1821   mdi->map_layer_alive = TRUE;
1822   mdi->mutex = vik_mutex_new();
1823   mdi->refresh_display = TRUE;
1824
1825   mdi->cache_dir = g_strdup ( vml->cache_dir );
1826   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1827   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1828   mdi->maptype = vml->maptype;
1829   mdi->cache_layout = vml->cache_layout;
1830
1831   mdi->mapcoord = ulm;
1832   mdi->redownload = download_method;
1833
1834   mdi->x0 = MIN(ulm.x, brm.x);
1835   mdi->xf = MAX(ulm.x, brm.x);
1836   mdi->y0 = MIN(ulm.y, brm.y);
1837   mdi->yf = MAX(ulm.y, brm.y);
1838
1839   mdi->mapstoget = 0;
1840
1841   MapCoord mcoord = mdi->mapcoord;
1842
1843   for (i = mdi->x0; i <= mdi->xf; i++) {
1844     mcoord.x = i;
1845     for (j = mdi->y0; j <= mdi->yf; j++) {
1846       mcoord.y = j;
1847       // Only count tiles from supported areas
1848       if ( is_in_area (map, mcoord) ) {
1849         get_filename ( mdi->cache_dir, mdi->cache_layout,
1850                        vik_map_source_get_uniq_id(map),
1851                        vik_map_source_get_name(map),
1852                        ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
1853                        vik_map_source_get_file_extension(map) );
1854         if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1855               mdi->mapstoget++;
1856       }
1857     }
1858   }
1859
1860   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1861
1862   if (mdi->mapstoget) {
1863     gchar *tmp;
1864     const gchar *fmt;
1865     fmt = ngettext("Downloading %d %s map...",
1866                    "Downloading %d %s maps...",
1867                    mdi->mapstoget);
1868     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1869
1870     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1871
1872     // launch the thread
1873     a_background_thread ( BACKGROUND_POOL_REMOTE,
1874                           VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1875                           tmp,                                /* description string */
1876                           (vik_thr_func) map_download_thread, /* function to call within thread */
1877                           mdi,                                /* pass along data */
1878                           (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1879                           (vik_thr_free_func) mdi_cancel_cleanup,
1880                           mdi->mapstoget );
1881     g_free ( tmp );
1882   }
1883   else
1884     mdi_free ( mdi );
1885 }
1886
1887 /**
1888  * vik_maps_layer_download_section:
1889  * @vml:  The Map Layer
1890  * @vvp:  The Viewport that the map is on
1891  * @ul:   Upper left coordinate of the area to be downloaded
1892  * @br:   Bottom right coordinate of the area to be downloaded
1893  * @zoom: The zoom level at which the maps are to be download
1894  *
1895  * Download a specified map area at a certain zoom level
1896  */
1897 void vik_maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom )
1898 {
1899   maps_layer_download_section (vml, vvp, ul, br, zoom, REDOWNLOAD_NONE);
1900 }
1901
1902 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1903 {
1904   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1905 }
1906
1907 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1908 {
1909   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1910 }
1911
1912 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1913 {
1914   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1915 }
1916
1917 /**
1918  * Display a simple dialog with information about this particular map tile
1919  */
1920 static void maps_layer_tile_info ( VikMapsLayer *vml )
1921 {
1922   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1923
1924   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1925   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1926   MapCoord ulm;
1927
1928   if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1929     return;
1930
1931   gchar *filename = NULL;
1932   gchar *source = NULL;
1933
1934   if ( vik_map_source_is_direct_file_access ( map ) ) {
1935     if ( vik_map_source_is_mbtiles ( map ) ) {
1936       filename = g_strdup ( vml->filename );
1937 #ifdef HAVE_SQLITE3_H
1938       // And whether to bother going into the SQL to check it's really there or not...
1939       gchar *exists = NULL;
1940       gint zoom = 17 - ulm.scale;
1941       if ( vml->mbtiles ) {
1942         GdkPixbuf *pixbuf = get_pixbuf_sql_exec ( vml->mbtiles, ulm.x, ulm.y, zoom );
1943         if ( pixbuf ) {
1944           exists = g_strdup ( _("YES") );
1945           g_object_unref ( G_OBJECT(pixbuf) );
1946         }
1947         else {
1948           exists = g_strdup ( _("NO") );
1949         }
1950       }
1951       else
1952         exists = g_strdup ( _("NO") );
1953       gint flip_y = (gint) pow(2, zoom)-1 - ulm.y;
1954       // NB Also handles .jpg automatically due to pixbuf_new_from () support - although just print png for now.
1955       source = g_strdup_printf ( _("Source: %s (%d%s%d%s%d.%s %s)"), filename, zoom, G_DIR_SEPARATOR_S, ulm.x, G_DIR_SEPARATOR_S, flip_y, "png", exists );
1956       g_free ( exists );
1957 #else
1958       source = g_strdup ( _("Source: Not available") );
1959 #endif
1960     }
1961     else if ( vik_map_source_is_osm_meta_tiles ( map ) ) {
1962       char path[PATH_MAX];
1963       xyz_to_meta(path, sizeof(path), vml->cache_dir, ulm.x, ulm.y, 17-ulm.scale );
1964       source = g_strdup ( path );
1965       filename = g_strdup ( path );
1966     }
1967     else {
1968       guint max_path_len = strlen(vml->cache_dir) + 40;
1969       filename = g_malloc ( max_path_len * sizeof(char) );
1970       get_filename ( vml->cache_dir, VIK_MAPS_CACHE_LAYOUT_OSM,
1971                      vik_map_source_get_uniq_id(map),
1972                      NULL,
1973                      ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1974                      vik_map_source_get_file_extension(map) );
1975       source = g_strconcat ( _("Source: file://"), filename, NULL );
1976     }
1977   }
1978   else {
1979     guint max_path_len = strlen(vml->cache_dir) + 40;
1980     filename = g_malloc ( max_path_len * sizeof(char) );
1981     get_filename ( vml->cache_dir, vml->cache_layout,
1982                    vik_map_source_get_uniq_id(map),
1983                    vik_map_source_get_name(map),
1984                    ulm.scale, ulm.z, ulm.x, ulm.y, filename, max_path_len,
1985                    vik_map_source_get_file_extension(map) );
1986     gchar *url = vik_map_source_default_get_url_display ( VIK_MAP_SOURCE_DEFAULT(map), &ulm );
1987     source = g_markup_printf_escaped ( _("Source: %s"), url );
1988     g_free ( url );
1989   }
1990
1991   GArray *array = g_array_new (FALSE, TRUE, sizeof(gchar*));
1992   g_array_append_val ( array, source );
1993
1994   gchar *filemsg = NULL;
1995   gchar *timemsg = NULL;
1996
1997   if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1998     filemsg = g_strconcat ( "Tile File: ", filename, NULL );
1999     // Get some timestamp information of the tile
2000     GStatBuf stat_buf;
2001     if ( g_stat ( filename, &stat_buf ) == 0 ) {
2002       gchar time_buf[64];
2003       strftime ( time_buf, sizeof(time_buf), "%c", gmtime((const time_t *)&stat_buf.st_mtime) );
2004       timemsg = g_strdup_printf ( _("Tile File Timestamp: %s"), time_buf );
2005     }
2006     else {
2007       timemsg = g_strdup ( _("Tile File Timestamp: Not Available") );
2008     }
2009     g_array_append_val ( array, filemsg );
2010     g_array_append_val ( array, timemsg );
2011   }
2012   else {
2013     filemsg = g_strdup_printf ( _("Tile File: %s [Not Available]"), filename );
2014     g_array_append_val ( array, filemsg );
2015   }
2016
2017   a_dialog_list (  VIK_GTK_WINDOW_FROM_LAYER(vml), _("Tile Information"), array, 5 );
2018   g_array_free ( array, FALSE );
2019
2020   g_free ( timemsg );
2021   g_free ( filemsg );
2022   g_free ( source );
2023   g_free ( filename );
2024 }
2025
2026 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
2027 {
2028   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2029     return FALSE;
2030   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
2031   {
2032     if ( event->button == 1 )
2033     {
2034       VikCoord ul, br;
2035       vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &ul );
2036       vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &br );
2037       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
2038       vml->dl_tool_x = vml->dl_tool_y = -1;
2039       return TRUE;
2040     }
2041     else
2042     {
2043       vik_viewport_screen_to_coord ( vvp, MAX(0, MIN(event->x, vml->dl_tool_x)), MAX(0, MIN(event->y, vml->dl_tool_y)), &(vml->redownload_ul) );
2044       vik_viewport_screen_to_coord ( vvp, MIN(vik_viewport_get_width(vvp), MAX(event->x, vml->dl_tool_x)), MIN(vik_viewport_get_height(vvp), MAX ( event->y, vml->dl_tool_y ) ), &(vml->redownload_br) );
2045
2046       vml->redownload_vvp = vvp;
2047
2048       vml->dl_tool_x = vml->dl_tool_y = -1;
2049
2050       if ( ! vml->dl_right_click_menu ) {
2051         GtkWidget *item;
2052         VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2053
2054         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
2055
2056         // Download options aren't for on disk only maps
2057         if ( ! (vik_map_source_is_mbtiles(map) ||
2058                 vik_map_source_is_direct_file_access(map) ||
2059                 vik_map_source_is_osm_meta_tiles(map)) ) {
2060
2061           item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
2062           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
2063           gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2064
2065           item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
2066           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
2067           gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2068
2069           item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
2070           g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
2071           gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
2072         }
2073
2074         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
2075         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
2076         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
2077         gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
2078       }
2079
2080       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
2081       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
2082     }
2083   }
2084   return FALSE;
2085 }
2086
2087 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
2088 {
2089   return vvp;
2090 }
2091
2092 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
2093 {
2094   MapCoord tmp;
2095   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
2096     return FALSE;
2097   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2098   if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
2099        vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
2100            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
2101            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
2102            &tmp ) ) {
2103     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
2104     return TRUE;
2105   }
2106   return FALSE;
2107 }
2108
2109 // A slightly better way of defining the menu callback information
2110 // This should be easier to extend/rework compared to previously
2111 typedef enum {
2112   MA_VML = 0,
2113   MA_VVP,
2114   MA_LAST
2115 } menu_array_index;
2116
2117 typedef gpointer menu_array_values[MA_LAST];
2118
2119 static void download_onscreen_maps ( menu_array_values values, gint redownload )
2120 {
2121   VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2122   VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2123   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
2124
2125   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
2126   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
2127
2128   VikCoord ul, br;
2129   MapCoord ulm, brm;
2130
2131   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
2132   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
2133
2134   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2135   if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
2136        vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
2137        vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
2138     start_download_thread ( vml, vvp, &ul, &br, redownload );
2139   else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
2140     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
2141     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
2142     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
2143     g_free(err);
2144   }
2145   else
2146     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
2147
2148 }
2149
2150 static void maps_layer_download_missing_onscreen_maps ( menu_array_values values )
2151 {
2152   download_onscreen_maps( values, REDOWNLOAD_NONE);
2153 }
2154
2155 static void maps_layer_download_new_onscreen_maps ( menu_array_values values )
2156 {
2157   download_onscreen_maps( values, REDOWNLOAD_NEW);
2158 }
2159
2160 static void maps_layer_redownload_all_onscreen_maps ( menu_array_values values )
2161 {
2162   download_onscreen_maps( values, REDOWNLOAD_ALL);
2163 }
2164
2165 static void maps_layer_about ( menu_array_values values )
2166 {
2167   VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2168   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2169
2170   if ( vik_map_source_get_license (map) )
2171     maps_show_license ( VIK_GTK_WINDOW_FROM_LAYER(vml), map );
2172   else
2173     a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2174                         vik_map_source_get_label (map) );
2175 }
2176
2177 /**
2178  * maps_layer_how_many_maps:
2179  * Copied from maps_layer_download_section but without the actual download and this returns a value
2180  */
2181 static gint maps_layer_how_many_maps ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom, gint redownload )
2182 {
2183   MapCoord ulm, brm;
2184   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2185
2186   if ( vik_map_source_is_direct_file_access ( map ) )
2187     return 0;
2188
2189   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
2190     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
2191     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
2192     return 0;
2193   }
2194
2195   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
2196   gint i, j;
2197
2198   mdi->vml = vml;
2199   mdi->vvp = vvp;
2200   mdi->map_layer_alive = TRUE;
2201   mdi->mutex = vik_mutex_new();
2202   mdi->refresh_display = FALSE;
2203
2204   mdi->cache_dir = g_strdup ( vml->cache_dir );
2205   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
2206   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
2207   mdi->maptype = vml->maptype;
2208   mdi->cache_layout = vml->cache_layout;
2209
2210   mdi->mapcoord = ulm;
2211   mdi->redownload = redownload;
2212
2213   mdi->x0 = MIN(ulm.x, brm.x);
2214   mdi->xf = MAX(ulm.x, brm.x);
2215   mdi->y0 = MIN(ulm.y, brm.y);
2216   mdi->yf = MAX(ulm.y, brm.y);
2217
2218   mdi->mapstoget = 0;
2219
2220   if ( mdi->redownload == REDOWNLOAD_ALL ) {
2221     mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
2222   }
2223   else {
2224     /* calculate how many we need */
2225     MapCoord mcoord = mdi->mapcoord;
2226     for (i = mdi->x0; i <= mdi->xf; i++) {
2227       mcoord.x = i;
2228       for (j = mdi->y0; j <= mdi->yf; j++) {
2229         mcoord.y = j;
2230         // Only count tiles from supported areas
2231         if ( is_in_area ( map, mcoord ) ) {
2232           get_filename ( mdi->cache_dir, mdi->cache_layout,
2233                          vik_map_source_get_uniq_id(map),
2234                          vik_map_source_get_name(map),
2235                          ulm.scale, ulm.z, i, j, mdi->filename_buf, mdi->maxlen,
2236                          vik_map_source_get_file_extension(map) );
2237           if ( mdi->redownload == REDOWNLOAD_NEW ) {
2238             // Assume the worst - always a new file
2239             // Absolute value would require a server lookup - but that is too slow
2240             mdi->mapstoget++;
2241           }
2242           else {
2243             if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
2244               // Missing
2245               mdi->mapstoget++;
2246             }
2247             else {
2248               if ( mdi->redownload == REDOWNLOAD_BAD ) {
2249                 /* see if this one is bad or what */
2250                 GError *gx = NULL;
2251                 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
2252                 if (gx || (!pixbuf)) {
2253                   mdi->mapstoget++;
2254                 }
2255                 break;
2256                 // Other download cases already considered or just ignored
2257               }
2258             }
2259           }
2260         }
2261       }
2262     }
2263   }
2264
2265   gint rv = mdi->mapstoget;
2266
2267   mdi_free ( mdi );
2268
2269   return rv;
2270 }
2271
2272 /**
2273  * maps_dialog_zoom_between:
2274  * This dialog is specific to the map layer, so it's here rather than in dialog.c
2275  */
2276 gboolean maps_dialog_zoom_between ( GtkWindow *parent,
2277                                     gchar *title,
2278                                     gchar *zoom_list[],
2279                                     gint default_zoom1,
2280                                     gint default_zoom2,
2281                                     gint *selected_zoom1,
2282                                     gint *selected_zoom2,
2283                                     gchar *download_list[],
2284                                     gint default_download,
2285                                     gint *selected_download )
2286 {
2287   GtkWidget *dialog = gtk_dialog_new_with_buttons ( title,
2288                                                     parent,
2289                                                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2290                                                     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2291                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2292                                                     NULL );
2293   gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2294   GtkWidget *response_w = NULL;
2295 #if GTK_CHECK_VERSION (2, 20, 0)
2296   response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
2297 #endif
2298   GtkWidget *zoom_label1 = gtk_label_new ( _("Zoom Start:") );
2299   GtkWidget *zoom_combo1 = vik_combo_box_text_new();
2300   gchar **s;
2301   for (s = zoom_list; *s; s++)
2302     vik_combo_box_text_append ( zoom_combo1, *s );
2303   gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo1), default_zoom1 );
2304
2305   GtkWidget *zoom_label2 = gtk_label_new ( _("Zoom End:") );
2306   GtkWidget *zoom_combo2 = vik_combo_box_text_new();
2307   for (s = zoom_list; *s; s++)
2308     vik_combo_box_text_append ( zoom_combo2, *s );
2309   gtk_combo_box_set_active ( GTK_COMBO_BOX(zoom_combo2), default_zoom2 );
2310
2311   GtkWidget *download_label = gtk_label_new(_("Download Maps Method:"));
2312   GtkWidget *download_combo = vik_combo_box_text_new();
2313   for (s = download_list; *s; s++)
2314     vik_combo_box_text_append ( download_combo, *s );
2315   gtk_combo_box_set_active ( GTK_COMBO_BOX(download_combo), default_download );
2316
2317   GtkTable *box = GTK_TABLE(gtk_table_new(3, 2, FALSE));
2318   gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label1), 0, 1, 0, 1);
2319   gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo1), 1, 2, 0, 1);
2320   gtk_table_attach_defaults (box, GTK_WIDGET(zoom_label2), 0, 1, 1, 2);
2321   gtk_table_attach_defaults (box, GTK_WIDGET(zoom_combo2), 1, 2, 1, 2);
2322   gtk_table_attach_defaults (box, GTK_WIDGET(download_label), 0, 1, 2, 3);
2323   gtk_table_attach_defaults (box, GTK_WIDGET(download_combo), 1, 2, 2, 3);
2324
2325   gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
2326
2327   if ( response_w )
2328     gtk_widget_grab_focus ( response_w );
2329
2330   gtk_widget_show_all ( dialog );
2331   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
2332     gtk_widget_destroy(dialog);
2333     return FALSE;
2334   }
2335
2336   // Return selected options
2337   *selected_zoom1 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo1) );
2338   *selected_zoom2 = gtk_combo_box_get_active ( GTK_COMBO_BOX(zoom_combo2) );
2339   *selected_download = gtk_combo_box_get_active ( GTK_COMBO_BOX(download_combo) );
2340
2341   gtk_widget_destroy(dialog);
2342   return TRUE;
2343 }
2344
2345 // My best guess of sensible limits
2346 #define REALLY_LARGE_AMOUNT_OF_TILES 5000
2347 #define CONFIRM_LARGE_AMOUNT_OF_TILES 500
2348
2349 /**
2350  * Get all maps in the region for zoom levels specified by the user
2351  * Sort of similar to trw_layer_download_map_along_track_cb function
2352  */
2353 static void maps_layer_download_all ( menu_array_values values )
2354 {
2355   VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2356   VikViewport *vvp = VIK_VIEWPORT(values[MA_VVP]);
2357
2358   // I don't think we should allow users to hammer the servers too much...
2359   // Delibrately not allowing lowest zoom levels
2360   // Still can give massive numbers to download
2361   // A screen size of 1600x1200 gives around 300,000 tiles between 1..128 when none exist before !!
2362   gchar *zoom_list[] = {"1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", NULL };
2363   gdouble zoom_vals[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};
2364
2365   gint selected_zoom1, selected_zoom2, default_zoom, lower_zoom;
2366   gint selected_download_method;
2367   
2368   gdouble cur_zoom = vik_viewport_get_zoom(vvp);
2369
2370   for (default_zoom = 0; default_zoom < sizeof(zoom_vals)/sizeof(gdouble); default_zoom++) {
2371     if (cur_zoom == zoom_vals[default_zoom])
2372       break;
2373   }
2374   default_zoom = (default_zoom == sizeof(zoom_vals)/sizeof(gdouble)) ? sizeof(zoom_vals)/sizeof(gdouble) - 1 : default_zoom;
2375
2376   // Default to only 2 zoom levels below the current one
2377   if (default_zoom > 1 )
2378     lower_zoom = default_zoom - 2;
2379   else
2380     lower_zoom = default_zoom;
2381
2382   // redownload method - needs to align with REDOWNLOAD* macro values
2383   gchar *download_list[] = { _("Missing"), _("Bad"), _("New"), _("Reload All"), NULL };
2384
2385   gchar *title = g_strdup_printf ( ("%s: %s"), vik_maps_layer_get_map_label (vml), _("Download for Zoom Levels") );
2386
2387   if ( ! maps_dialog_zoom_between ( VIK_GTK_WINDOW_FROM_LAYER(vml),
2388                                     title,
2389                                     zoom_list,
2390                                     lower_zoom,
2391                                     default_zoom,
2392                                     &selected_zoom1,
2393                                     &selected_zoom2,
2394                                     download_list,
2395                                     REDOWNLOAD_NONE, // AKA Missing
2396                                     &selected_download_method ) ) {
2397     // Cancelled
2398     g_free ( title );
2399     return;
2400   }
2401   g_free ( title );
2402
2403   // Find out new current positions
2404   gdouble min_lat, max_lat, min_lon, max_lon;
2405   VikCoord vc_ul, vc_br;
2406   vik_viewport_get_min_max_lat_lon ( vvp, &min_lat, &max_lat, &min_lon, &max_lon );
2407   struct LatLon ll_ul = { max_lat, min_lon };
2408   struct LatLon ll_br = { min_lat, max_lon };
2409   vik_coord_load_from_latlon ( &vc_ul, vik_viewport_get_coord_mode (vvp), &ll_ul );
2410   vik_coord_load_from_latlon ( &vc_br, vik_viewport_get_coord_mode (vvp), &ll_br );
2411
2412   // Get Maps Count - call for each zoom level (in reverse)
2413   // With REDOWNLOAD_NEW this is a possible maximum
2414   // With REDOWNLOAD_NONE this only missing ones - however still has a server lookup per tile
2415   gint map_count = 0;
2416   gint zz;
2417   for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2418     map_count = map_count + maps_layer_how_many_maps ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2419   }
2420
2421   g_debug ("vikmapslayer: download request map count %d for method %d", map_count, selected_download_method);
2422
2423   // Absolute protection of hammering a map server
2424   if ( map_count > REALLY_LARGE_AMOUNT_OF_TILES ) {
2425     gchar *str = g_strdup_printf (_("You are not allowed to download more than %d tiles in one go (requested %d)"), REALLY_LARGE_AMOUNT_OF_TILES, map_count);
2426     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), str );
2427     g_free (str);
2428     return;
2429   }
2430
2431   // Confirm really want to do this
2432   if ( map_count > CONFIRM_LARGE_AMOUNT_OF_TILES ) {
2433     gchar *str = g_strdup_printf (_("Do you really want to download %d tiles?"), map_count);
2434     gboolean ans = a_dialog_yes_or_no ( VIK_GTK_WINDOW_FROM_LAYER(vml), str, NULL );
2435     g_free (str);
2436     if ( ! ans )
2437       return;
2438   }
2439
2440   // Get Maps - call for each zoom level (in reverse)
2441   for ( zz = selected_zoom2; zz >= selected_zoom1; zz-- ) {
2442     maps_layer_download_section ( vml, vvp, &vc_ul, &vc_br, zoom_vals[zz], selected_download_method );
2443   }
2444 }
2445
2446 /**
2447  *
2448  */
2449 static void maps_layer_flush ( menu_array_values values )
2450 {
2451   VikMapsLayer *vml = VIK_MAPS_LAYER(values[MA_VML]);
2452   a_mapcache_flush_type ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)) );
2453 }
2454
2455 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
2456 {
2457   GtkWidget *item;
2458   static menu_array_values values;
2459   values[MA_VML] = vml;
2460   values[MA_VVP] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
2461
2462   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
2463
2464   item = gtk_menu_item_new();
2465   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
2466   gtk_widget_show ( item );
2467
2468   // Download options aren't for on disk only maps
2469   if ( ! (vik_map_source_is_mbtiles(map) ||
2470           vik_map_source_is_direct_file_access(map) ||
2471           vik_map_source_is_osm_meta_tiles(map)) ) {
2472     /* Now with icons */
2473     item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
2474     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
2475     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), values );
2476     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2477     gtk_widget_show ( item );
2478
2479     if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
2480       item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
2481       gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
2482       g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), values );
2483       gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2484       gtk_widget_show ( item );
2485     }
2486
2487     item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
2488     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
2489     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), values );
2490     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2491     gtk_widget_show ( item );
2492
2493     item = gtk_image_menu_item_new_with_mnemonic ( _("Download Maps in _Zoom Levels...") );
2494     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_DND_MULTIPLE, GTK_ICON_SIZE_MENU) );
2495     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_all), values );
2496     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2497     gtk_widget_show ( item );
2498   }
2499
2500   item = gtk_image_menu_item_new_from_stock ( GTK_STOCK_ABOUT, NULL );
2501   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_about), values );
2502   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2503   gtk_widget_show ( item );
2504
2505   // Typical users shouldn't need to use this functionality - so debug only ATM
2506   if ( vik_debug ) {
2507     item = gtk_image_menu_item_new_with_mnemonic ( _("Flush Map Cache") );
2508     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU) );
2509     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_flush), values );
2510     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
2511     gtk_widget_show ( item );
2512   }
2513 }
2514
2515 /**
2516  * Enable downloading maps of the current screen area either 'new' or 'everything'
2517  */
2518 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
2519 {
2520   if ( !vml ) return;
2521   if ( !vvp ) return;
2522
2523   static menu_array_values values;
2524   values[MA_VML] = vml;
2525   values[MA_VVP] = vvp;
2526
2527   if ( only_new )
2528     // Get only new maps
2529     maps_layer_download_new_onscreen_maps ( values );
2530   else
2531     // Redownload everything
2532     maps_layer_redownload_all_onscreen_maps ( values );
2533 }