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