]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
Make more portable .vik file, as don't save the map cache directory if it's the map...
[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  * UTM multi-zone stuff by Kit Transue <notlostyet@didactek.com>
7  * Dynamic map type by Guilhem Bonnefille <guilhem.bonnefille@gmail.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 // TODO: Make these configurable
30 #define MAX_TILES 1000
31
32 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
33 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
34
35 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
36
37 #include <gtk/gtk.h>
38 #include <gdk-pixbuf/gdk-pixdata.h>
39 #include <glib.h>
40 #include <glib/gstdio.h>
41 #include <glib/gi18n.h>
42
43 #ifdef HAVE_STRING_H
44 #include <string.h>
45 #endif
46 #ifdef HAVE_MATH_H
47 #include <math.h>
48 #endif
49
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53
54 #include "viking.h"
55 #include "vikmapsourcedefault.h"
56 #include "maputils.h"
57 #include "mapcache.h"
58 #include "background.h"
59 #include "preferences.h"
60 #include "vikmapslayer.h"
61 #include "icons/icons.h"
62
63 /****** MAP TYPES ******/
64
65 static GList *__map_types = NULL;
66
67 #define NUM_MAP_TYPES g_list_length(__map_types)
68
69 /* List of label for each map type */
70 static gchar **params_maptypes = NULL;
71
72 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
73 static guint *params_maptypes_ids = NULL;
74
75 /******** MAPZOOMS *********/
76
77 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 };
78 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 };
79 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 };
80
81 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
82
83 /**************************/
84
85
86 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
87 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
88 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
89 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
90 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
91 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
92 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
93 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
94 static void maps_layer_free ( VikMapsLayer *vml );
95 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
96 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
97 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
98 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
99 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
100 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
101 static guint map_uniq_id_to_index ( guint uniq_id );
102
103
104 static VikLayerParamScale params_scales[] = {
105   /* min, max, step, digits (decimal places) */
106  { 0, 255, 3, 0 }, /* alpha */
107 };
108
109 static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
110 static VikLayerParamData directory_default ( void )
111 {
112   VikLayerParamData data;
113   data.s = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
114   return data;
115 }
116 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
117 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
118
119 VikLayerParam maps_layer_params[] = {
120   { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
121   { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
122   { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
123     N_("Control the Alpha value for transparency effects"), alpha_default },
124   { 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 },
125   { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
126     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 },
127   { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
128     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."),
129     mapzoom_default },
130 };
131
132 enum {
133   PARAM_MAPTYPE=0,
134   PARAM_CACHE_DIR,
135   PARAM_ALPHA,
136   PARAM_AUTODOWNLOAD,
137   PARAM_ONLYMISSING,
138   PARAM_MAPZOOM,
139   NUM_PARAMS
140 };
141
142 static VikToolInterface maps_tools[] = {
143   { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
144     (VikToolConstructorFunc) maps_layer_download_create,
145     NULL,
146     NULL,
147     NULL,
148     (VikToolMouseFunc) maps_layer_download_click,
149     NULL,
150     (VikToolMouseFunc) maps_layer_download_release,
151     NULL,
152     FALSE,
153     GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
154 };
155
156 VikLayerInterface vik_maps_layer_interface = {
157   "Map",
158   N_("Map"),
159   "<control><shift>M",
160   &vikmapslayer_pixbuf,
161
162   maps_tools,
163   sizeof(maps_tools) / sizeof(maps_tools[0]),
164
165   maps_layer_params,
166   NUM_PARAMS,
167   NULL,
168   0,
169
170   VIK_MENU_ITEM_ALL,
171
172   (VikLayerFuncCreate)                  maps_layer_new,
173   (VikLayerFuncRealize)                 NULL,
174   (VikLayerFuncPostRead)                maps_layer_post_read,
175   (VikLayerFuncFree)                    maps_layer_free,
176
177   (VikLayerFuncProperties)              NULL,
178   (VikLayerFuncDraw)                    maps_layer_draw,
179   (VikLayerFuncChangeCoordMode)         NULL,
180
181   (VikLayerFuncSetMenuItemsSelection)   NULL,
182   (VikLayerFuncGetMenuItemsSelection)   NULL,
183
184   (VikLayerFuncAddMenuItems)            maps_layer_add_menu_items,
185   (VikLayerFuncSublayerAddMenuItems)    NULL,
186
187   (VikLayerFuncSublayerRenameRequest)   NULL,
188   (VikLayerFuncSublayerToggleVisible)   NULL,
189   (VikLayerFuncSublayerTooltip)         NULL,
190   (VikLayerFuncLayerTooltip)            maps_layer_tooltip,
191   (VikLayerFuncLayerSelected)           NULL,
192
193   (VikLayerFuncMarshall)                maps_layer_marshall,
194   (VikLayerFuncUnmarshall)              maps_layer_unmarshall,
195
196   (VikLayerFuncSetParam)                maps_layer_set_param,
197   (VikLayerFuncGetParam)                maps_layer_get_param,
198
199   (VikLayerFuncReadFileData)            NULL,
200   (VikLayerFuncWriteFileData)           NULL,
201
202   (VikLayerFuncDeleteItem)              NULL,
203   (VikLayerFuncCutItem)                 NULL,
204   (VikLayerFuncCopyItem)                NULL,
205   (VikLayerFuncPasteItem)               NULL,
206   (VikLayerFuncFreeCopiedItem)          NULL,
207   (VikLayerFuncDragDropRequest)         NULL,
208
209   (VikLayerFuncSelectClick)             NULL,
210   (VikLayerFuncSelectMove)              NULL,
211   (VikLayerFuncSelectRelease)           NULL,
212   (VikLayerFuncSelectedViewportMenu)    NULL,
213 };
214
215 struct _VikMapsLayer {
216   VikLayer vl;
217   guint maptype;
218   gchar *cache_dir;
219   guint8 alpha;
220   guint mapzoom_id;
221   gdouble xmapzoom, ymapzoom;
222
223   gboolean autodownload;
224   gboolean adl_only_missing;
225   VikCoord *last_center;
226   gdouble last_xmpp;
227   gdouble last_ympp;
228
229   gint dl_tool_x, dl_tool_y;
230
231   GtkMenu *dl_right_click_menu;
232   VikCoord redownload_ul, redownload_br; /* right click menu only */
233   VikViewport *redownload_vvp;
234
235   gboolean license_notice_shown; // FALSE for new maps only, otherwise
236                                  // TRUE for saved maps & other layer changes as we don't need to show it again
237 };
238
239 enum { REDOWNLOAD_NONE = 0,    /* download only missing maps */
240        REDOWNLOAD_BAD,         /* download missing and bad maps */
241        REDOWNLOAD_NEW,         /* download missing maps that are newer on server only */
242        REDOWNLOAD_ALL,         /* download all maps */
243        DOWNLOAD_OR_REFRESH };  /* download missing maps and refresh cache */
244
245 static VikLayerParam prefs[] = {
246   { 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") },
247 };
248
249 void maps_layer_init ()
250 {
251   VikLayerParamData tmp;
252   tmp.s = maps_layer_default_dir();
253   a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
254 }
255
256 /****************************************/
257 /******** MAPS LAYER TYPES **************/
258 /****************************************/
259
260 int _get_index_for_id ( guint id )
261 {
262   int index = 0 ;
263   while (params_maptypes_ids[index] != 0)
264   {
265     if (params_maptypes_ids[index] == id)
266       return index;
267     index++;
268   }
269   return -1;
270 }
271
272 void _add_map_source ( guint id, const char *label, VikMapSource *map )
273 {
274   gsize len = 0;
275   if (params_maptypes)
276     len = g_strv_length (params_maptypes);
277   /* Add the label */
278   params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
279   params_maptypes[len] = g_strdup (label);
280   params_maptypes[len+1] = NULL;
281
282   /* Add the id */
283   params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
284   params_maptypes_ids[len] = id;
285   params_maptypes_ids[len+1] = 0;
286
287   /* We have to clone */
288   VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
289   /* Register the clone in the list */
290   __map_types = g_list_append(__map_types, clone);
291
292   /* Hack
293      We have to ensure the mode LayerParam references the up-to-date
294      GLists.
295   */
296   /*
297   memcpy(&maps_layer_params[0].widget_data, &params_maptypes, sizeof(gpointer));
298   memcpy(&maps_layer_params[0].extra_widget_data, &params_maptypes_ids, sizeof(gpointer));
299   */
300   maps_layer_params[0].widget_data = params_maptypes;
301   maps_layer_params[0].extra_widget_data = params_maptypes_ids;
302 }
303
304 void _update_map_source ( const char *label, VikMapSource *map, int index )
305 {
306   GList *item = g_list_nth (__map_types, index);
307   g_object_unref (item->data);
308   item->data = g_object_ref (map);
309   /* Change previous data */
310   g_free (params_maptypes[index]);
311   params_maptypes[index] = g_strdup (label);
312 }
313
314 /**
315  * maps_layer_register_map_source:
316  * @map: the new VikMapSource
317  *
318  * Register a new VikMapSource.
319  * Override existing one (equality of id).
320  */
321 void maps_layer_register_map_source ( VikMapSource *map )
322 {
323   g_assert(map != NULL);
324   
325   guint id = vik_map_source_get_uniq_id(map);
326   const char *label = vik_map_source_get_label(map);
327   g_assert(label != NULL);
328
329   int previous = map_uniq_id_to_index (id);
330   if (previous != NUM_MAP_TYPES)
331   {
332     _update_map_source (label, map, previous);
333   }
334   else
335   {
336     _add_map_source (id, label, map);
337   }
338 }
339
340 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
341 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
342 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
343
344 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
345 {
346   return(vml->maptype);
347 }
348
349 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
350 {
351   return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
352 }
353
354 /****************************************/
355 /******** CACHE DIR STUFF ***************/
356 /****************************************/
357
358 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
359 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
360 #define MAPS_CACHE_DIR maps_layer_default_dir()
361
362 #ifdef WINDOWS
363 #include <io.h>
364 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
365 #define LOCAL_MAPS_DIR "VIKING-MAPS"
366 #elif defined __APPLE__
367 #include <stdlib.h>
368 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
369 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
370 #else /* POSIX */
371 #include <stdlib.h>
372 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
373 #define LOCAL_MAPS_DIR ".viking-maps"
374 #endif
375
376 gchar *maps_layer_default_dir ()
377 {
378   static gchar *defaultdir = NULL;
379   if ( ! defaultdir )
380   {
381     /* Thanks to Mike Davison for the $VIKING_MAPS usage */
382     const gchar *mapdir = g_getenv("VIKING_MAPS");
383     if ( mapdir ) {
384       defaultdir = g_strdup ( mapdir );
385     } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
386       defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
387     } else {
388       const gchar *home = g_get_home_dir();
389       if (!home || g_access(home, W_OK))
390         home = g_get_home_dir ();
391       if ( home )
392         defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
393       else
394         defaultdir = g_strdup ( LOCAL_MAPS_DIR );
395     }
396     if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
397     {
398       /* Add the separator at the end */
399       gchar *tmp = defaultdir;
400       defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
401       g_free(tmp);
402     }
403     g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
404   }
405   return defaultdir;
406 }
407
408 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
409 {
410   if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
411   {
412     g_mkdir ( vml->cache_dir, 0777 );
413   }
414 }
415
416 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
417 {
418   guint len;
419   g_assert ( vml != NULL);
420   g_free ( vml->cache_dir );
421   vml->cache_dir = NULL;
422
423   if ( dir == NULL || dir[0] == '\0' )
424   {
425     if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
426       vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
427   }
428   else
429   {
430     len = strlen(dir);
431     if ( dir[len-1] != G_DIR_SEPARATOR )
432     {
433       vml->cache_dir = g_malloc ( len+2 );
434       strncpy ( vml->cache_dir, dir, len );
435       vml->cache_dir[len] = G_DIR_SEPARATOR;
436       vml->cache_dir[len+1] = '\0';
437     }
438     else
439       vml->cache_dir = g_strdup ( dir );
440   }
441   maps_layer_mkdir_if_default_dir ( vml );
442 }
443
444 /****************************************/
445 /******** GOBJECT STUFF *****************/
446 /****************************************/
447
448 GType vik_maps_layer_get_type ()
449 {
450   static GType vml_type = 0;
451
452   if (!vml_type)
453   {
454     static const GTypeInfo vml_info =
455     {
456       sizeof (VikMapsLayerClass),
457       NULL, /* base_init */
458       NULL, /* base_finalize */
459       NULL, /* class init */
460       NULL, /* class_finalize */
461       NULL, /* class_data */
462       sizeof (VikMapsLayer),
463       0,
464       NULL /* instance init */
465     };
466     vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
467   }
468
469   return vml_type;
470 }
471
472 /****************************************/
473 /************** PARAMETERS **************/
474 /****************************************/
475
476 static guint map_index_to_uniq_id (guint8 index)
477 {
478   g_assert ( index < NUM_MAP_TYPES );
479   return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
480 }
481
482 static guint map_uniq_id_to_index ( guint uniq_id )
483 {
484   gint i;
485   for ( i = 0; i < NUM_MAP_TYPES; i++ )
486     if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
487       return i;
488   return NUM_MAP_TYPES; /* no such thing */
489 }
490
491 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
492 {
493   // When loading from a file don't need the license reminder
494   if ( is_file_operation )
495     vml->license_notice_shown = TRUE;
496
497   switch ( id )
498   {
499     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
500     case PARAM_MAPTYPE: {
501       gint maptype = map_uniq_id_to_index(data.u);
502       if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
503       else vml->maptype = maptype;
504       break;
505     }
506     case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
507     case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
508     case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
509     case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
510                           vml->mapzoom_id = data.u;
511                           vml->xmapzoom = __mapzooms_x [data.u];
512                           vml->ymapzoom = __mapzooms_y [data.u];
513                         }else g_warning (_("Unknown Map Zoom")); break;
514   }
515   return TRUE;
516 }
517
518 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
519 {
520   VikLayerParamData rv;
521   switch ( id )
522   {
523     case PARAM_CACHE_DIR:
524       /* Only save a blank when the map cache location equals the default
525           On reading in, when it is blank then the default is reconstructed
526           Since the default changes dependent on the user and OS, it means the resultant file is more portable */
527       if ( is_file_operation && vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 )
528         rv.s = "";
529       else
530         rv.s = vml->cache_dir ? vml->cache_dir : "";
531       break;
532     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
533     case PARAM_ALPHA: rv.u = vml->alpha; break;
534     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
535     case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
536     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
537   }
538   return rv;
539 }
540
541 /****************************************/
542 /****** CREATING, COPYING, FREEING ******/
543 /****************************************/
544
545 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
546 {
547   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
548   vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
549
550   vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
551
552   vml->dl_tool_x = vml->dl_tool_y = -1;
553   vml->last_center = NULL;
554   vml->last_xmpp = 0.0;
555   vml->last_ympp = 0.0;
556
557   vml->dl_right_click_menu = NULL;
558   vml->license_notice_shown = FALSE;
559
560   return vml;
561 }
562
563 static void maps_layer_free ( VikMapsLayer *vml )
564 {
565   g_free ( vml->cache_dir );
566   vml->cache_dir = NULL;
567   if ( vml->dl_right_click_menu )
568     g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
569   g_free(vml->last_center);
570   vml->last_center = NULL;
571 }
572
573 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
574 {
575   if (from_file != TRUE)
576   {
577     /* If this method is not called in file reading context
578      * it is called in GUI context.
579      * So, we can check if we have to inform the user about inconsistency */
580     VikViewportDrawMode vp_drawmode;
581     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
582     VikMapSource *map = NULL;
583  
584     vp_drawmode = vik_viewport_get_drawmode ( vp );
585     map = MAPS_LAYER_NTH_TYPE(vml->maptype);
586     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
587       const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
588       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
589       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
590       g_free(msg);
591     }
592
593     if (vik_map_source_get_license (map) != NULL) {
594       if ( ! vml->license_notice_shown ) {
595         a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
596                           vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
597         vml->license_notice_shown = TRUE;
598       }
599     }
600   }
601 }
602
603 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
604 {
605   return vik_maps_layer_get_map_label ( vml );
606 }
607
608 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
609 {
610   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
611 }
612
613 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
614 {
615   VikMapsLayer *rv = maps_layer_new ( vvp );
616   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
617   return rv;
618 }
619
620 /*********************/
621 /****** DRAWING ******/
622 /*********************/
623
624 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
625 {
626   guchar *pixels;
627   gint width, height, iii, jjj;
628
629   if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
630   {
631     GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
632     g_object_unref(G_OBJECT(pixbuf));
633     pixbuf = tmp;
634   }
635
636   pixels = gdk_pixbuf_get_pixels(pixbuf);
637   width = gdk_pixbuf_get_width(pixbuf);
638   height = gdk_pixbuf_get_height(pixbuf);
639
640   /* r,g,b,a,r,g,b,a.... */
641   for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
642   {
643     pixels += 3;
644     *pixels++ = alpha;
645   }
646   return pixbuf;
647 }
648
649 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
650 {
651   GdkPixbuf *tmp;
652   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
653   tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
654   g_object_unref ( G_OBJECT(pixbuf) );
655   return tmp;
656 }
657
658 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
659 {
660   GdkPixbuf *pixbuf;
661
662   /* get the thing */
663   pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
664                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
665
666   if ( ! pixbuf ) {
667     if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
668       g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
669                    vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
670     else
671       g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
672                    vml->cache_dir, mode,
673                    mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
674
675     if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
676     {
677       GError *gx = NULL;
678       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
679
680       /* free the pixbuf on error */
681       if (gx)
682       {
683         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
684           g_warning ( _("Couldn't open image file: %s"), gx->message );
685
686         g_error_free ( gx );
687         if ( pixbuf )
688           g_object_unref ( G_OBJECT(pixbuf) );
689         pixbuf = NULL;
690       } else {
691           if ( vml->alpha < 255 )
692             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
693           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
694             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
695
696           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
697               mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
698               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
699       }
700     }
701   }
702   return pixbuf;
703 }
704
705 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
706 {
707   const VikCoord *center = vik_viewport_get_center ( vvp );
708
709   if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
710     /* D'n'D pan in action: do not download */
711     return FALSE;
712
713   // TEMPORARY HACK
714   // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
715   // Allow MapQuest Zoom Level up to 19
716   // TODO: This should be made a property of the map source and then use that value
717   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
718   if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
719     return FALSE;
720
721   if (vml->last_center == NULL) {
722     VikCoord *new_center = g_malloc(sizeof(VikCoord));
723     *new_center = *center;
724     vml->last_center = new_center;
725     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
726     vml->last_ympp = vik_viewport_get_ympp(vvp);
727     return TRUE;
728   }
729
730   /* TODO: perhaps vik_coord_diff() */
731   if (vik_coord_equals(vml->last_center, center)
732       && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
733       && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
734     return FALSE;
735
736   *(vml->last_center) = *center;
737     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
738     vml->last_ympp = vik_viewport_get_ympp(vvp);
739   return TRUE;
740 }
741
742 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
743 {
744   MapCoord ulm, brm;
745   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
746   gdouble yzoom = vik_viewport_get_ympp ( vvp );
747   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
748   gboolean existence_only = FALSE;
749
750   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
751     xshrinkfactor = vml->xmapzoom / xzoom;
752     yshrinkfactor = vml->ymapzoom / yzoom;
753     xzoom = vml->xmapzoom;
754     yzoom = vml->xmapzoom;
755     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
756          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
757       if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
758         g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
759         existence_only = TRUE;
760       }
761       else {
762         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
763         return;
764       }
765     }
766   }
767
768   /* coord -> ID */
769   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
770   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
771        vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
772
773     /* loop & draw */
774     gint x, y;
775     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
776     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
777     gint mode = vik_map_source_get_uniq_id(map);
778
779     VikCoord coord;
780     gint xx, yy, width, height;
781     GdkPixbuf *pixbuf;
782
783     // Prevent the program grinding to a halt if trying to deal with thousands of tiles
784     //  which can happen when using a small fixed zoom level and viewing large areas.
785     // Also prevents very large number of tile download requests
786     gint tiles = (xmax-xmin) * (ymax-ymin);
787     if ( tiles > MAX_TILES ) {
788       g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
789       existence_only = TRUE;
790     }
791
792     guint max_path_len = strlen(vml->cache_dir) + 40;
793     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
794
795     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
796       g_debug("%s: Starting autodownload", __FUNCTION__);
797       if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
798         // Try to download newer tiles
799         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
800       else
801         // Download only missing tiles
802         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
803     }
804
805     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
806       for ( x = xmin; x <= xmax; x++ ) {
807         for ( y = ymin; y <= ymax; y++ ) {
808           ulm.x = x;
809           ulm.y = y;
810           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
811           if ( pixbuf ) {
812             width = gdk_pixbuf_get_width ( pixbuf );
813             height = gdk_pixbuf_get_height ( pixbuf );
814
815             vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
816             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
817             xx -= (width/2);
818             yy -= (height/2);
819
820             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
821           }
822         }
823       }
824     } else { /* tilesize is known, don't have to keep converting coords */
825       gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
826       gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
827       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
828       gint tilesize_x_ceil = ceil ( tilesize_x );
829       gint tilesize_y_ceil = ceil ( tilesize_y );
830       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
831       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
832       gdouble xx, yy; gint xx_tmp, yy_tmp;
833       gint base_yy, xend, yend;
834
835       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
836       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
837
838       vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
839       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
840       xx = xx_tmp; yy = yy_tmp;
841       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
842        * eg if tile size 128, shrinkfactor 0.333 */
843       xx -= (tilesize_x/2);
844       base_yy = yy - (tilesize_y/2);
845
846       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
847         yy = base_yy;
848         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
849           ulm.x = x;
850           ulm.y = y;
851
852           if ( existence_only ) {
853             if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
854               g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
855                            vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
856             else
857               g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
858                            vml->cache_dir, mode,
859                            ulm.scale, ulm.z, ulm.x, ulm.y );
860             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
861               GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
862               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
863             }
864           } else {
865             int scale_inc;
866             for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
867               /* try with correct then smaller zooms */
868               int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
869               MapCoord ulm2 = ulm;
870               ulm2.x = ulm.x / scale_factor;
871               ulm2.y = ulm.y / scale_factor;
872               ulm2.scale = ulm.scale + scale_inc;
873               pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
874               if ( pixbuf ) {
875                 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
876                 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
877 #ifdef DEBUG
878                 printf("maps_layer_draw_section - x=%d, y=%d, z=%d, src_x=%d, src_y=%d, xx=%d, yy=%d - %x\n", ulm.x, ulm.y, ulm.scale, src_x, src_y, (int)xx, (int)yy, vvp);
879 #endif
880                 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
881                 break;
882               }
883             }
884             if ( !pixbuf ) {
885               /* retry with bigger zooms */
886               int scale_dec;
887               for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
888                 int pict_x, pict_y;
889                 int scale_factor = 1 << scale_dec;  /*  2^scale_dec */
890                 MapCoord ulm2 = ulm;
891                 ulm2.x = ulm.x * scale_factor;
892                 ulm2.y = ulm.y * scale_factor;
893                 ulm2.scale = ulm.scale - scale_dec;
894                 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
895                   for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
896                     MapCoord ulm3 = ulm2;
897                     ulm3.x += pict_x;
898                     ulm3.y += pict_y;
899                     pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
900                     if ( pixbuf ) {
901                       gint src_x = 0;
902                       gint src_y = 0;
903                       gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
904                       gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
905                       vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
906                     }
907                   }
908                 }
909               }
910             }
911           }
912
913           yy += tilesize_y;
914         }
915         xx += tilesize_x;
916       }
917     }
918
919     g_free ( path_buf );
920   }
921 }
922
923 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
924 {
925   if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
926   {
927     VikCoord ul, br;
928
929     /* Copyright */
930     gdouble level = vik_viewport_get_zoom ( vvp );
931     LatLonBBox bbox;
932     vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
933     vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
934
935     /* Logo */
936     const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
937     vik_viewport_add_logo ( vvp, logo );
938
939     /* get corner coords */
940     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
941       /* UTM multi-zone stuff by Kit Transue */
942       gchar leftmost_zone, rightmost_zone, i;
943       leftmost_zone = vik_viewport_leftmost_zone( vvp );
944       rightmost_zone = vik_viewport_rightmost_zone( vvp );
945       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
946         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
947         maps_layer_draw_section ( vml, vvp, &ul, &br );
948       }
949     }
950     else {
951       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
952       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
953
954       maps_layer_draw_section ( vml, vvp, &ul, &br );
955     }
956   }
957 }
958
959 /*************************/
960 /****** DOWNLOADING ******/
961 /*************************/
962
963 /* pass along data to thread, exists even if layer is deleted. */
964 typedef struct {
965   gchar *cache_dir;
966   gchar *filename_buf;
967   gint x0, y0, xf, yf;
968   MapCoord mapcoord;
969   gint maptype;
970   gint maxlen;
971   gint mapstoget;
972   gint redownload;
973   gboolean refresh_display;
974   VikMapsLayer *vml;
975   VikViewport *vvp;
976   gboolean map_layer_alive;
977   GMutex *mutex;
978 } MapDownloadInfo;
979
980 static void mdi_free ( MapDownloadInfo *mdi )
981 {
982   g_mutex_free(mdi->mutex);
983   g_free ( mdi->cache_dir );
984   mdi->cache_dir = NULL;
985   g_free ( mdi->filename_buf );
986   mdi->filename_buf = NULL;
987   g_free ( mdi );
988 }
989
990 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
991 {
992   MapDownloadInfo *mdi = ptr;
993   g_mutex_lock(mdi->mutex);
994   mdi->map_layer_alive = FALSE;
995   g_mutex_unlock(mdi->mutex);
996 }
997
998 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
999 {
1000   void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
1001   guint donemaps = 0;
1002   gint x, y;
1003   for ( x = mdi->x0; x <= mdi->xf; x++ )
1004   {
1005     for ( y = mdi->y0; y <= mdi->yf; y++ )
1006     {
1007       gboolean remove_mem_cache = FALSE;
1008       gboolean need_download = FALSE;
1009       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1010                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1011                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1012
1013       donemaps++;
1014       int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1015       if (res != 0) {
1016         vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1017         return -1;
1018       }
1019
1020       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1021         need_download = TRUE;
1022         remove_mem_cache = TRUE;
1023
1024       } else {  /* in case map file already exists */
1025         switch (mdi->redownload) {
1026           case REDOWNLOAD_NONE:
1027             continue;
1028
1029           case REDOWNLOAD_BAD:
1030           {
1031             /* see if this one is bad or what */
1032             GError *gx = NULL;
1033             GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1034             if (gx || (!pixbuf)) {
1035               g_remove ( mdi->filename_buf );
1036               need_download = TRUE;
1037               remove_mem_cache = TRUE;
1038               g_error_free ( gx );
1039
1040             } else {
1041               g_object_unref ( pixbuf );
1042             }
1043             break;
1044           }
1045
1046           case REDOWNLOAD_NEW:
1047             need_download = TRUE;
1048             remove_mem_cache = TRUE;
1049             break;
1050
1051           case REDOWNLOAD_ALL:
1052             /* FIXME: need a better way than to erase file in case of server/network problem */
1053             g_remove ( mdi->filename_buf );
1054             need_download = TRUE;
1055             remove_mem_cache = TRUE;
1056             break;
1057
1058           case DOWNLOAD_OR_REFRESH:
1059             remove_mem_cache = TRUE;
1060             break;
1061
1062           default:
1063             g_warning ( "redownload state %d unknown\n", mdi->redownload);
1064         }
1065       }
1066
1067       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1068
1069       if (need_download) {
1070         if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1071           continue;
1072       }
1073
1074       g_mutex_lock(mdi->mutex);
1075       if (remove_mem_cache)
1076           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 );
1077       if (mdi->refresh_display && mdi->map_layer_alive) {
1078         /* TODO: check if it's on visible area */
1079         vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1080       }
1081       g_mutex_unlock(mdi->mutex);
1082       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1083
1084     }
1085   }
1086   vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1087   g_mutex_lock(mdi->mutex);
1088   if (mdi->map_layer_alive)
1089     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1090   g_mutex_unlock(mdi->mutex); 
1091   return 0;
1092 }
1093
1094 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1095 {
1096   if ( mdi->mapcoord.x || mdi->mapcoord.y )
1097   {
1098     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1099                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1100                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1101     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1102     {
1103       g_remove ( mdi->filename_buf );
1104     }
1105   }
1106 }
1107
1108 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1109 {
1110   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1111   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1112   MapCoord ulm, brm;
1113   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1114
1115   // Don't ever attempt download on direct access
1116   if ( vik_map_source_is_direct_file_access ( map ) )
1117     return;
1118
1119   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
1120     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1121   {
1122     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1123     gint a, b;
1124
1125     mdi->vml = vml;
1126     mdi->vvp = vvp;
1127     mdi->map_layer_alive = TRUE;
1128     mdi->mutex = g_mutex_new();
1129     mdi->refresh_display = TRUE;
1130
1131     /* cache_dir and buffer for dest filename */
1132     mdi->cache_dir = g_strdup ( vml->cache_dir );
1133     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1134     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1135     mdi->maptype = vml->maptype;
1136
1137     mdi->mapcoord = ulm;
1138
1139     mdi->redownload = redownload;
1140
1141     mdi->x0 = MIN(ulm.x, brm.x);
1142     mdi->xf = MAX(ulm.x, brm.x);
1143     mdi->y0 = MIN(ulm.y, brm.y);
1144     mdi->yf = MAX(ulm.y, brm.y);
1145
1146     mdi->mapstoget = 0;
1147
1148     if ( mdi->redownload ) {
1149       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1150     } else {
1151       /* calculate how many we need */
1152       for ( a = mdi->x0; a <= mdi->xf; a++ )
1153       {
1154         for ( b = mdi->y0; b <= mdi->yf; b++ )
1155         {
1156           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1157                        vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1158                        ulm.z, a, b );
1159           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1160             mdi->mapstoget++;
1161         }
1162       }
1163     }
1164
1165     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1166
1167     if ( mdi->mapstoget )
1168     {
1169       const gchar *tmp_str;
1170       gchar *tmp;
1171
1172       if (redownload) 
1173       {
1174         if (redownload == REDOWNLOAD_BAD)
1175           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1176         else
1177           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1178       } 
1179       else 
1180       {
1181         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1182       }
1183       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1184  
1185       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1186       /* launch the thread */
1187       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1188                             tmp,                                              /* description string */
1189                             (vik_thr_func) map_download_thread,               /* function to call within thread */
1190                             mdi,                                              /* pass along data */
1191                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
1192                             (vik_thr_free_func) mdi_cancel_cleanup,
1193                             mdi->mapstoget );
1194       g_free ( tmp );
1195     }
1196     else
1197       mdi_free ( mdi );
1198   }
1199 }
1200
1201 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1202 {
1203   MapCoord ulm, brm;
1204   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1205
1206   // Don't ever attempt download on direct access
1207   if ( vik_map_source_is_direct_file_access ( map ) )
1208     return;
1209
1210   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
1211     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1212     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1213     return;
1214   }
1215
1216   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1217   gint i, j;
1218
1219   mdi->vml = vml;
1220   mdi->vvp = vvp;
1221   mdi->map_layer_alive = TRUE;
1222   mdi->mutex = g_mutex_new();
1223   mdi->refresh_display = TRUE;
1224
1225   mdi->cache_dir = g_strdup ( vml->cache_dir );
1226   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1227   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1228   mdi->maptype = vml->maptype;
1229
1230   mdi->mapcoord = ulm;
1231
1232   mdi->redownload = REDOWNLOAD_NONE;
1233
1234   mdi->x0 = MIN(ulm.x, brm.x);
1235   mdi->xf = MAX(ulm.x, brm.x);
1236   mdi->y0 = MIN(ulm.y, brm.y);
1237   mdi->yf = MAX(ulm.y, brm.y);
1238
1239   mdi->mapstoget = 0;
1240
1241   for (i = mdi->x0; i <= mdi->xf; i++) {
1242     for (j = mdi->y0; j <= mdi->yf; j++) {
1243       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1244                    vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1245                    ulm.z, i, j );
1246       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1247             mdi->mapstoget++;
1248     }
1249   }
1250
1251   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1252
1253   if (mdi->mapstoget) {
1254     gchar *tmp;
1255     const gchar *fmt;
1256     fmt = ngettext("Downloading %d %s map...",
1257                    "Downloading %d %s maps...",
1258                    mdi->mapstoget);
1259     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1260
1261     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1262       /* launch the thread */
1263     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1264       tmp,                                /* description string */
1265       (vik_thr_func) map_download_thread, /* function to call within thread */
1266       mdi,                                /* pass along data */
1267       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1268       (vik_thr_free_func) mdi_cancel_cleanup,
1269       mdi->mapstoget );
1270     g_free ( tmp );
1271   }
1272   else
1273     mdi_free ( mdi );
1274 }
1275
1276 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1277 {
1278   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1279 }
1280
1281 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1282 {
1283   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1284 }
1285
1286 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1287 {
1288   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1289 }
1290
1291 /**
1292  * Display a simple dialog with information about this particular map tile
1293  */
1294 static void maps_layer_tile_info ( VikMapsLayer *vml )
1295 {
1296   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1297
1298   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1299   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1300   MapCoord ulm;
1301
1302   if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1303     return;
1304
1305   gchar *filename = NULL;
1306   gchar *message = NULL;
1307   gchar *source = NULL;
1308
1309   if ( vik_map_source_is_direct_file_access ( map ) ) {
1310     filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1311     source = g_strconcat ( "file://", filename, NULL );
1312   }
1313   else {
1314         filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1315     source = g_strdup_printf ( "http://%s%s",
1316                                vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1317                                vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1318   }
1319
1320   if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1321
1322     // Get some timestamp information of the tile
1323     struct stat stat_buf;
1324     if ( g_stat ( filename, &stat_buf ) == 0 ) {
1325       time_t file_time = stat_buf.st_mtime;
1326 #if GLIB_CHECK_VERSION(2,26,0)
1327       GDateTime* gdt = g_date_time_new_from_unix_utc ( file_time );
1328       gchar *time = g_date_time_format ( gdt, "%c" );
1329 #else
1330       GDate* gdate = g_date_new ();
1331       g_date_set_time_t ( gdate, file_time );
1332       char time[32];
1333       g_date_strftime ( time, sizeof(time), "%c", gdate );
1334       g_date_free ( gdate );
1335 #endif
1336       message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time );
1337
1338 #if GLIB_CHECK_VERSION(2,26,0)
1339       g_free ( time );
1340       g_date_time_unref ( gdt);
1341 #endif
1342     }
1343   }
1344   else
1345     message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1346
1347   // Show the info
1348   a_dialog_info_msg (  VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1349
1350   g_free ( message );
1351   g_free ( source );
1352   g_free ( filename );
1353 }
1354
1355 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1356 {
1357   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1358     return FALSE;
1359   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1360   {
1361     if ( event->button == 1 )
1362     {
1363       VikCoord ul, br;
1364       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 );
1365       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 );
1366       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1367       vml->dl_tool_x = vml->dl_tool_y = -1;
1368       return TRUE;
1369     }
1370     else
1371     {
1372       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) );
1373       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) );
1374
1375       vml->redownload_vvp = vvp;
1376
1377       vml->dl_tool_x = vml->dl_tool_y = -1;
1378
1379       if ( ! vml->dl_right_click_menu ) {
1380         GtkWidget *item;
1381         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1382
1383         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1384         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1385         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1386
1387         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1388         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1389         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1390
1391         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1392         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1393         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1394
1395         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1396         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1397         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1398         gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1399       }
1400
1401       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1402       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1403     }
1404   }
1405   return FALSE;
1406 }
1407
1408 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1409 {
1410   return vvp;
1411 }
1412
1413 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1414 {
1415   MapCoord tmp;
1416   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1417     return FALSE;
1418   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1419   if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1420        vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1421            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1422            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1423            &tmp ) ) {
1424     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1425     return TRUE;
1426   }
1427   return FALSE;
1428
1429  
1430 #if 0
1431   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1432   {
1433     VikCoord coord;
1434     MapCoord mapcoord;
1435     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1436     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1437                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1438                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1439                 &mapcoord ) ) {
1440       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1441                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1442                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1443
1444       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1445       g_free ( filename_buf );
1446       vik_layer_emit_update ( VIK_LAYER(vml) );
1447       return TRUE;
1448     }
1449   }
1450   return FALSE;
1451 #endif
1452 }
1453
1454 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1455 {
1456   VikMapsLayer *vml = vml_vvp[0];
1457   VikViewport *vvp = vml_vvp[1];
1458   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1459
1460   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1461   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1462
1463   VikCoord ul, br;
1464   MapCoord ulm, brm;
1465
1466   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1467   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1468
1469   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1470   if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1471        vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1472        vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1473     start_download_thread ( vml, vvp, &ul, &br, redownload );
1474   else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1475     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1476     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1477     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1478     g_free(err);
1479   }
1480   else
1481     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1482
1483 }
1484
1485 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1486 {
1487   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1488 }
1489
1490 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1491 {
1492   download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1493 }
1494
1495 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1496 {
1497   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1498 }
1499
1500 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1501 {
1502   static gpointer pass_along[2];
1503   GtkWidget *item;
1504   pass_along[0] = vml;
1505   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1506
1507   item = gtk_menu_item_new();
1508   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1509   gtk_widget_show ( item );
1510
1511   /* Now with icons */
1512   item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1513     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1514   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1515   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1516   gtk_widget_show ( item );
1517
1518   if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1519     item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1520     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1521     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1522     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1523     gtk_widget_show ( item );
1524   }
1525
1526   item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1527   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1528   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1529   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1530   gtk_widget_show ( item );
1531 }
1532
1533 /**
1534  * Enable downloading maps of the current screen area either 'new' or 'everything'
1535  */
1536 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1537 {
1538   if ( !vml ) return;
1539   if ( !vvp ) return;
1540
1541   static gpointer pass_along[2];
1542   pass_along[0] = vml;
1543   pass_along[1] = vvp;
1544
1545   if ( only_new )
1546     // Get only new maps
1547     maps_layer_download_new_onscreen_maps ( pass_along );
1548   else
1549     // Redownload everything
1550     maps_layer_redownload_all_onscreen_maps ( pass_along );
1551 }