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