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