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