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