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