]> git.street.me.uk Git - andy/viking.git/blob - src/vikmapslayer.c
6c005dd1fd54923aa6993b8bf06408e37a01a532
[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 maplayer 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: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
524     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
525     case PARAM_ALPHA: rv.u = vml->alpha; break;
526     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
527     case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
528     case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
529   }
530   return rv;
531 }
532
533 /****************************************/
534 /****** CREATING, COPYING, FREEING ******/
535 /****************************************/
536
537 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
538 {
539   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
540   vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
541
542   vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
543
544   vml->dl_tool_x = vml->dl_tool_y = -1;
545   vml->last_center = NULL;
546   vml->last_xmpp = 0.0;
547   vml->last_ympp = 0.0;
548
549   vml->dl_right_click_menu = NULL;
550   vml->license_notice_shown = FALSE;
551
552   return vml;
553 }
554
555 static void maps_layer_free ( VikMapsLayer *vml )
556 {
557   g_free ( vml->cache_dir );
558   vml->cache_dir = NULL;
559   if ( vml->dl_right_click_menu )
560     g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
561   g_free(vml->last_center);
562   vml->last_center = NULL;
563 }
564
565 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
566 {
567   if (from_file != TRUE)
568   {
569     /* If this method is not called in file reading context
570      * it is called in GUI context.
571      * So, we can check if we have to inform the user about inconsistency */
572     VikViewportDrawMode vp_drawmode;
573     VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
574     VikMapSource *map = NULL;
575  
576     vp_drawmode = vik_viewport_get_drawmode ( vp );
577     map = MAPS_LAYER_NTH_TYPE(vml->maptype);
578     if (vik_map_source_get_drawmode(map) != vp_drawmode) {
579       const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
580       gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
581       a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
582       g_free(msg);
583     }
584
585     if (vik_map_source_get_license (map) != NULL) {
586       if ( ! vml->license_notice_shown ) {
587         a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
588                           vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
589         vml->license_notice_shown = TRUE;
590       }
591     }
592   }
593 }
594
595 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
596 {
597   return vik_maps_layer_get_map_label ( vml );
598 }
599
600 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
601 {
602   vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
603 }
604
605 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
606 {
607   VikMapsLayer *rv = maps_layer_new ( vvp );
608   vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
609   return rv;
610 }
611
612 /*********************/
613 /****** DRAWING ******/
614 /*********************/
615
616 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
617 {
618   guchar *pixels;
619   gint width, height, iii, jjj;
620
621   if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
622   {
623     GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
624     g_object_unref(G_OBJECT(pixbuf));
625     pixbuf = tmp;
626   }
627
628   pixels = gdk_pixbuf_get_pixels(pixbuf);
629   width = gdk_pixbuf_get_width(pixbuf);
630   height = gdk_pixbuf_get_height(pixbuf);
631
632   /* r,g,b,a,r,g,b,a.... */
633   for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
634   {
635     pixels += 3;
636     *pixels++ = alpha;
637   }
638   return pixbuf;
639 }
640
641 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
642 {
643   GdkPixbuf *tmp;
644   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
645   tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
646   g_object_unref ( G_OBJECT(pixbuf) );
647   return tmp;
648 }
649
650 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
651 {
652   GdkPixbuf *pixbuf;
653
654   /* get the thing */
655   pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
656                             mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
657
658   if ( ! pixbuf ) {
659     if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
660       g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
661                    vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
662     else
663       g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
664                    vml->cache_dir, mode,
665                    mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
666
667     if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
668     {
669       GError *gx = NULL;
670       pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
671
672       /* free the pixbuf on error */
673       if (gx)
674       {
675         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
676           g_warning ( _("Couldn't open image file: %s"), gx->message );
677
678         g_error_free ( gx );
679         if ( pixbuf )
680           g_object_unref ( G_OBJECT(pixbuf) );
681         pixbuf = NULL;
682       } else {
683           if ( vml->alpha < 255 )
684             pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
685           if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
686             pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
687
688           a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y, 
689               mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
690               mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
691       }
692     }
693   }
694   return pixbuf;
695 }
696
697 static gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
698 {
699   const VikCoord *center = vik_viewport_get_center ( vvp );
700
701   if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
702     /* D'n'D pan in action: do not download */
703     return FALSE;
704
705   // TEMPORARY HACK
706   // Prevent requests for downloading tiles at Zoom Level 19 and above for most map types
707   // Allow MapQuest Zoom Level up to 19
708   // TODO: This should be made a property of the map source and then use that value
709   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
710   if ( (vml->maptype != 19 && map_utils_mpp_to_scale (xzoom) < -1) || (vml->maptype == 19 && map_utils_mpp_to_scale (xzoom) < -2) )
711     return FALSE;
712
713   if (vml->last_center == NULL) {
714     VikCoord *new_center = g_malloc(sizeof(VikCoord));
715     *new_center = *center;
716     vml->last_center = new_center;
717     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
718     vml->last_ympp = vik_viewport_get_ympp(vvp);
719     return TRUE;
720   }
721
722   /* TODO: perhaps vik_coord_diff() */
723   if (vik_coord_equals(vml->last_center, center)
724       && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
725       && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
726     return FALSE;
727
728   *(vml->last_center) = *center;
729     vml->last_xmpp = vik_viewport_get_xmpp(vvp);
730     vml->last_ympp = vik_viewport_get_ympp(vvp);
731   return TRUE;
732 }
733
734 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
735 {
736   MapCoord ulm, brm;
737   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
738   gdouble yzoom = vik_viewport_get_ympp ( vvp );
739   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
740   gboolean existence_only = FALSE;
741
742   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
743     xshrinkfactor = vml->xmapzoom / xzoom;
744     yshrinkfactor = vml->ymapzoom / yzoom;
745     xzoom = vml->xmapzoom;
746     yzoom = vml->xmapzoom;
747     if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
748          yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
749       if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR ) {
750         g_debug ( "%s: existence_only due to SHRINKFACTORS", __FUNCTION__ );
751         existence_only = TRUE;
752       }
753       else {
754         g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
755         return;
756       }
757     }
758   }
759
760   /* coord -> ID */
761   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
762   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
763        vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
764
765     /* loop & draw */
766     gint x, y;
767     gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
768     gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
769     gint mode = vik_map_source_get_uniq_id(map);
770
771     VikCoord coord;
772     gint xx, yy, width, height;
773     GdkPixbuf *pixbuf;
774
775     // Prevent the program grinding to a halt if trying to deal with thousands of tiles
776     //  which can happen when using a small fixed zoom level and viewing large areas.
777     // Also prevents very large number of tile download requests
778     gint tiles = (xmax-xmin) * (ymax-ymin);
779     if ( tiles > MAX_TILES ) {
780       g_debug ( "%s: existence_only due to wanting too many tiles (%d)", __FUNCTION__, tiles );
781       existence_only = TRUE;
782     }
783
784     guint max_path_len = strlen(vml->cache_dir) + 40;
785     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
786
787     if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
788       g_debug("%s: Starting autodownload", __FUNCTION__);
789       if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
790         // Try to download newer tiles
791         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
792       else
793         // Download only missing tiles
794         start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
795     }
796
797     if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
798       for ( x = xmin; x <= xmax; x++ ) {
799         for ( y = ymin; y <= ymax; y++ ) {
800           ulm.x = x;
801           ulm.y = y;
802           pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
803           if ( pixbuf ) {
804             width = gdk_pixbuf_get_width ( pixbuf );
805             height = gdk_pixbuf_get_height ( pixbuf );
806
807             vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
808             vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
809             xx -= (width/2);
810             yy -= (height/2);
811
812             vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
813           }
814         }
815       }
816     } else { /* tilesize is known, don't have to keep converting coords */
817       gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
818       gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
819       /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
820       gint tilesize_x_ceil = ceil ( tilesize_x );
821       gint tilesize_y_ceil = ceil ( tilesize_y );
822       gint8 xinc = (ulm.x == xmin) ? 1 : -1;
823       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
824       gdouble xx, yy; gint xx_tmp, yy_tmp;
825       gint base_yy, xend, yend;
826
827       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
828       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
829
830       vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
831       vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
832       xx = xx_tmp; yy = yy_tmp;
833       /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
834        * eg if tile size 128, shrinkfactor 0.333 */
835       xx -= (tilesize_x/2);
836       base_yy = yy - (tilesize_y/2);
837
838       for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
839         yy = base_yy;
840         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
841           ulm.x = x;
842           ulm.y = y;
843
844           if ( existence_only ) {
845             if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
846               g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
847                            vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
848             else
849               g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
850                            vml->cache_dir, mode,
851                            ulm.scale, ulm.z, ulm.x, ulm.y );
852             if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
853               GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
854               vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
855             }
856           } else {
857             int scale_inc;
858             for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
859               /* try with correct then smaller zooms */
860               int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
861               MapCoord ulm2 = ulm;
862               ulm2.x = ulm.x / scale_factor;
863               ulm2.y = ulm.y / scale_factor;
864               ulm2.scale = ulm.scale + scale_inc;
865               pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
866               if ( pixbuf ) {
867                 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
868                 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
869 #ifdef DEBUG
870                 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);
871 #endif
872                 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
873                 break;
874               }
875             }
876             if ( !pixbuf ) {
877               /* retry with bigger zooms */
878               int scale_dec;
879               for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
880                 int pict_x, pict_y;
881                 int scale_factor = 1 << scale_dec;  /*  2^scale_dec */
882                 MapCoord ulm2 = ulm;
883                 ulm2.x = ulm.x * scale_factor;
884                 ulm2.y = ulm.y * scale_factor;
885                 ulm2.scale = ulm.scale - scale_dec;
886                 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
887                   for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
888                     MapCoord ulm3 = ulm2;
889                     ulm3.x += pict_x;
890                     ulm3.y += pict_y;
891                     pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
892                     if ( pixbuf ) {
893                       gint src_x = 0;
894                       gint src_y = 0;
895                       gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
896                       gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
897                       vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
898                     }
899                   }
900                 }
901               }
902             }
903           }
904
905           yy += tilesize_y;
906         }
907         xx += tilesize_x;
908       }
909     }
910
911     g_free ( path_buf );
912   }
913 }
914
915 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
916 {
917   if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
918   {
919     VikCoord ul, br;
920
921     /* Copyright */
922     gdouble level = vik_viewport_get_zoom ( vvp );
923     LatLonBBox bbox;
924     vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
925     vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
926
927     /* Logo */
928     const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
929     vik_viewport_add_logo ( vvp, logo );
930
931     /* get corner coords */
932     if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
933       /* UTM multi-zone stuff by Kit Transue */
934       gchar leftmost_zone, rightmost_zone, i;
935       leftmost_zone = vik_viewport_leftmost_zone( vvp );
936       rightmost_zone = vik_viewport_rightmost_zone( vvp );
937       for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
938         vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
939         maps_layer_draw_section ( vml, vvp, &ul, &br );
940       }
941     }
942     else {
943       vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
944       vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
945
946       maps_layer_draw_section ( vml, vvp, &ul, &br );
947     }
948   }
949 }
950
951 /*************************/
952 /****** DOWNLOADING ******/
953 /*************************/
954
955 /* pass along data to thread, exists even if layer is deleted. */
956 typedef struct {
957   gchar *cache_dir;
958   gchar *filename_buf;
959   gint x0, y0, xf, yf;
960   MapCoord mapcoord;
961   gint maptype;
962   gint maxlen;
963   gint mapstoget;
964   gint redownload;
965   gboolean refresh_display;
966   VikMapsLayer *vml;
967   VikViewport *vvp;
968   gboolean map_layer_alive;
969   GMutex *mutex;
970 } MapDownloadInfo;
971
972 static void mdi_free ( MapDownloadInfo *mdi )
973 {
974   g_mutex_free(mdi->mutex);
975   g_free ( mdi->cache_dir );
976   mdi->cache_dir = NULL;
977   g_free ( mdi->filename_buf );
978   mdi->filename_buf = NULL;
979   g_free ( mdi );
980 }
981
982 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
983 {
984   MapDownloadInfo *mdi = ptr;
985   g_mutex_lock(mdi->mutex);
986   mdi->map_layer_alive = FALSE;
987   g_mutex_unlock(mdi->mutex);
988 }
989
990 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
991 {
992   void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
993   guint donemaps = 0;
994   gint x, y;
995   for ( x = mdi->x0; x <= mdi->xf; x++ )
996   {
997     for ( y = mdi->y0; y <= mdi->yf; y++ )
998     {
999       gboolean remove_mem_cache = FALSE;
1000       gboolean need_download = FALSE;
1001       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1002                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1003                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
1004
1005       donemaps++;
1006       int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
1007       if (res != 0) {
1008         vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1009         return -1;
1010       }
1011
1012       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
1013         need_download = TRUE;
1014         remove_mem_cache = TRUE;
1015
1016       } else {  /* in case map file already exists */
1017         switch (mdi->redownload) {
1018           case REDOWNLOAD_NONE:
1019             continue;
1020
1021           case REDOWNLOAD_BAD:
1022           {
1023             /* see if this one is bad or what */
1024             GError *gx = NULL;
1025             GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1026             if (gx || (!pixbuf)) {
1027               g_remove ( mdi->filename_buf );
1028               need_download = TRUE;
1029               remove_mem_cache = TRUE;
1030               g_error_free ( gx );
1031
1032             } else {
1033               g_object_unref ( pixbuf );
1034             }
1035             break;
1036           }
1037
1038           case REDOWNLOAD_NEW:
1039             need_download = TRUE;
1040             remove_mem_cache = TRUE;
1041             break;
1042
1043           case REDOWNLOAD_ALL:
1044             /* FIXME: need a better way than to erase file in case of server/network problem */
1045             g_remove ( mdi->filename_buf );
1046             need_download = TRUE;
1047             remove_mem_cache = TRUE;
1048             break;
1049
1050           case DOWNLOAD_OR_REFRESH:
1051             remove_mem_cache = TRUE;
1052             break;
1053
1054           default:
1055             g_warning ( "redownload state %d unknown\n", mdi->redownload);
1056         }
1057       }
1058
1059       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1060
1061       if (need_download) {
1062         if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1063           continue;
1064       }
1065
1066       g_mutex_lock(mdi->mutex);
1067       if (remove_mem_cache)
1068           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 );
1069       if (mdi->refresh_display && mdi->map_layer_alive) {
1070         /* TODO: check if it's on visible area */
1071         vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1072       }
1073       g_mutex_unlock(mdi->mutex);
1074       mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1075
1076     }
1077   }
1078   vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1079   g_mutex_lock(mdi->mutex);
1080   if (mdi->map_layer_alive)
1081     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1082   g_mutex_unlock(mdi->mutex); 
1083   return 0;
1084 }
1085
1086 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1087 {
1088   if ( mdi->mapcoord.x || mdi->mapcoord.y )
1089   {
1090     g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1091                      mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1092                      mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1093     if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1094     {
1095       g_remove ( mdi->filename_buf );
1096     }
1097   }
1098 }
1099
1100 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1101 {
1102   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1103   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1104   MapCoord ulm, brm;
1105   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1106
1107   // Don't ever attempt download on direct access
1108   if ( vik_map_source_is_direct_file_access ( map ) )
1109     return;
1110
1111   if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) 
1112     && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1113   {
1114     MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1115     gint a, b;
1116
1117     mdi->vml = vml;
1118     mdi->vvp = vvp;
1119     mdi->map_layer_alive = TRUE;
1120     mdi->mutex = g_mutex_new();
1121     mdi->refresh_display = TRUE;
1122
1123     /* cache_dir and buffer for dest filename */
1124     mdi->cache_dir = g_strdup ( vml->cache_dir );
1125     mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1126     mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1127     mdi->maptype = vml->maptype;
1128
1129     mdi->mapcoord = ulm;
1130
1131     mdi->redownload = redownload;
1132
1133     mdi->x0 = MIN(ulm.x, brm.x);
1134     mdi->xf = MAX(ulm.x, brm.x);
1135     mdi->y0 = MIN(ulm.y, brm.y);
1136     mdi->yf = MAX(ulm.y, brm.y);
1137
1138     mdi->mapstoget = 0;
1139
1140     if ( mdi->redownload ) {
1141       mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1142     } else {
1143       /* calculate how many we need */
1144       for ( a = mdi->x0; a <= mdi->xf; a++ )
1145       {
1146         for ( b = mdi->y0; b <= mdi->yf; b++ )
1147         {
1148           g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1149                        vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1150                        ulm.z, a, b );
1151           if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1152             mdi->mapstoget++;
1153         }
1154       }
1155     }
1156
1157     mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1158
1159     if ( mdi->mapstoget )
1160     {
1161       const gchar *tmp_str;
1162       gchar *tmp;
1163
1164       if (redownload) 
1165       {
1166         if (redownload == REDOWNLOAD_BAD)
1167           tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1168         else
1169           tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1170       } 
1171       else 
1172       {
1173         tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1174       }
1175       tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1176  
1177       g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1178       /* launch the thread */
1179       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1180                             tmp,                                              /* description string */
1181                             (vik_thr_func) map_download_thread,               /* function to call within thread */
1182                             mdi,                                              /* pass along data */
1183                             (vik_thr_free_func) mdi_free,                     /* function to free pass along data */
1184                             (vik_thr_free_func) mdi_cancel_cleanup,
1185                             mdi->mapstoget );
1186       g_free ( tmp );
1187     }
1188     else
1189       mdi_free ( mdi );
1190   }
1191 }
1192
1193 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1194 {
1195   MapCoord ulm, brm;
1196   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1197
1198   // Don't ever attempt download on direct access
1199   if ( vik_map_source_is_direct_file_access ( map ) )
1200     return;
1201
1202   if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm) 
1203     || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1204     g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1205     return;
1206   }
1207
1208   MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1209   gint i, j;
1210
1211   mdi->vml = vml;
1212   mdi->vvp = vvp;
1213   mdi->map_layer_alive = TRUE;
1214   mdi->mutex = g_mutex_new();
1215   mdi->refresh_display = TRUE;
1216
1217   mdi->cache_dir = g_strdup ( vml->cache_dir );
1218   mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1219   mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1220   mdi->maptype = vml->maptype;
1221
1222   mdi->mapcoord = ulm;
1223
1224   mdi->redownload = REDOWNLOAD_NONE;
1225
1226   mdi->x0 = MIN(ulm.x, brm.x);
1227   mdi->xf = MAX(ulm.x, brm.x);
1228   mdi->y0 = MIN(ulm.y, brm.y);
1229   mdi->yf = MAX(ulm.y, brm.y);
1230
1231   mdi->mapstoget = 0;
1232
1233   for (i = mdi->x0; i <= mdi->xf; i++) {
1234     for (j = mdi->y0; j <= mdi->yf; j++) {
1235       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1236                    vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1237                    ulm.z, i, j );
1238       if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1239             mdi->mapstoget++;
1240     }
1241   }
1242
1243   mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1244
1245   if (mdi->mapstoget) {
1246     gchar *tmp;
1247     const gchar *fmt;
1248     fmt = ngettext("Downloading %d %s map...",
1249                    "Downloading %d %s maps...",
1250                    mdi->mapstoget);
1251     tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1252
1253     g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1254       /* launch the thread */
1255     a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1256       tmp,                                /* description string */
1257       (vik_thr_func) map_download_thread, /* function to call within thread */
1258       mdi,                                /* pass along data */
1259       (vik_thr_free_func) mdi_free,       /* function to free pass along data */
1260       (vik_thr_free_func) mdi_cancel_cleanup,
1261       mdi->mapstoget );
1262     g_free ( tmp );
1263   }
1264   else
1265     mdi_free ( mdi );
1266 }
1267
1268 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1269 {
1270   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1271 }
1272
1273 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1274 {
1275   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1276 }
1277
1278 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1279 {
1280   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1281 }
1282
1283 /**
1284  * Display a simple dialog with information about this particular map tile
1285  */
1286 static void maps_layer_tile_info ( VikMapsLayer *vml )
1287 {
1288   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1289
1290   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1291   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1292   MapCoord ulm;
1293
1294   if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1295     return;
1296
1297   gchar *filename = NULL;
1298   gchar *message = NULL;
1299   gchar *source = NULL;
1300
1301   if ( vik_map_source_is_direct_file_access ( map ) ) {
1302     filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1303     source = g_strconcat ( "file://", filename, NULL );
1304   }
1305   else {
1306         filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1307     source = g_strdup_printf ( "http://%s%s",
1308                                vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1309                                vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1310   }
1311
1312   if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1313
1314     // Get some timestamp information of the tile
1315     struct stat stat_buf;
1316     if ( g_stat ( filename, &stat_buf ) == 0 ) {
1317       time_t file_time = stat_buf.st_mtime;
1318 #if GLIB_CHECK_VERSION(2,26,0)
1319       GDateTime* gdt = g_date_time_new_from_unix_utc ( file_time );
1320       gchar *time = g_date_time_format ( gdt, "%c" );
1321 #else
1322       char time[20];
1323       strftime(time, 20, "%Y-%m-%d %H:%M:%S", localtime(&file_time));
1324 #endif
1325       message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time );
1326
1327 #if GLIB_CHECK_VERSION(2,26,0)
1328       g_free ( time );
1329       g_date_time_unref ( gdt);
1330 #endif
1331     }
1332   }
1333   else
1334     message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1335
1336   // Show the info
1337   a_dialog_info_msg (  VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1338
1339   g_free ( message );
1340   g_free ( source );
1341   g_free ( filename );
1342 }
1343
1344 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1345 {
1346   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1347     return FALSE;
1348   if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1349   {
1350     if ( event->button == 1 )
1351     {
1352       VikCoord ul, br;
1353       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 );
1354       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 );
1355       start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1356       vml->dl_tool_x = vml->dl_tool_y = -1;
1357       return TRUE;
1358     }
1359     else
1360     {
1361       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) );
1362       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) );
1363
1364       vml->redownload_vvp = vvp;
1365
1366       vml->dl_tool_x = vml->dl_tool_y = -1;
1367
1368       if ( ! vml->dl_right_click_menu ) {
1369         GtkWidget *item;
1370         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1371
1372         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1373         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1374         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1375
1376         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1377         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1378         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1379
1380         item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1381         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1382         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1383
1384         item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1385         gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1386         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1387         gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1388       }
1389
1390       gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1391       gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1392     }
1393   }
1394   return FALSE;
1395 }
1396
1397 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1398 {
1399   return vvp;
1400 }
1401
1402 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1403 {
1404   MapCoord tmp;
1405   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1406     return FALSE;
1407   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1408   if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1409        vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1410            vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1411            vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1412            &tmp ) ) {
1413     vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1414     return TRUE;
1415   }
1416   return FALSE;
1417
1418  
1419 #if 0
1420   if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1421   {
1422     VikCoord coord;
1423     MapCoord mapcoord;
1424     vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1425     if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1426                 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1427                 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1428                 &mapcoord ) ) {
1429       gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1430                      vml->cache_dir, __map_types[vml->maptype].uniq_id,
1431                      mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1432
1433       __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1434       g_free ( filename_buf );
1435       vik_layer_emit_update ( VIK_LAYER(vml) );
1436       return TRUE;
1437     }
1438   }
1439   return FALSE;
1440 #endif
1441 }
1442
1443 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1444 {
1445   VikMapsLayer *vml = vml_vvp[0];
1446   VikViewport *vvp = vml_vvp[1];
1447   VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1448
1449   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1450   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1451
1452   VikCoord ul, br;
1453   MapCoord ulm, brm;
1454
1455   vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1456   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1457
1458   VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1459   if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1460        vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1461        vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1462     start_download_thread ( vml, vvp, &ul, &br, redownload );
1463   else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1464     const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1465     gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1466     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1467     g_free(err);
1468   }
1469   else
1470     a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1471
1472 }
1473
1474 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1475 {
1476   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1477 }
1478
1479 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1480 {
1481   download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1482 }
1483
1484 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1485 {
1486   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1487 }
1488
1489 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1490 {
1491   static gpointer pass_along[2];
1492   GtkWidget *item;
1493   pass_along[0] = vml;
1494   pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1495
1496   item = gtk_menu_item_new();
1497   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1498   gtk_widget_show ( item );
1499
1500   /* Now with icons */
1501   item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1502     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1503   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1504   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1505   gtk_widget_show ( item );
1506
1507   if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1508     item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1509     gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1510     g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1511     gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1512     gtk_widget_show ( item );
1513   }
1514
1515   item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1516   gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1517   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1518   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1519   gtk_widget_show ( item );
1520 }
1521
1522 /**
1523  * Enable downloading maps of the current screen area either 'new' or 'everything'
1524  */
1525 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1526 {
1527   if ( !vml ) return;
1528   if ( !vvp ) return;
1529
1530   static gpointer pass_along[2];
1531   pass_along[0] = vml;
1532   pass_along[1] = vvp;
1533
1534   if ( only_new )
1535     // Get only new maps
1536     maps_layer_download_new_onscreen_maps ( pass_along );
1537   else
1538     // Redownload everything
1539     maps_layer_redownload_all_onscreen_maps ( pass_along );
1540 }