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