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