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