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