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