2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
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>
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.
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.
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
29 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
30 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
32 #define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
35 #include <gdk-pixbuf/gdk-pixdata.h>
37 #include <glib/gstdio.h>
38 #include <glib/gi18n.h>
52 #include "vikmapsourcedefault.h"
54 #include "background.h"
55 #include "preferences.h"
56 #include "vikmapslayer.h"
57 #include "icons/icons.h"
59 /****** MAP TYPES ******/
61 static GList *__map_types = NULL;
63 #define NUM_MAP_TYPES g_list_length(__map_types)
65 /* List of label for each map type */
66 static gchar **params_maptypes = NULL;
68 /* Corresponding IDS. (Cf. field uniq_id in VikMapsLayer struct) */
69 static guint *params_maptypes_ids = NULL;
71 /******** MAPZOOMS *********/
73 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 };
74 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 };
75 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 };
77 #define NUM_MAPZOOMS (sizeof(params_mapzooms)/sizeof(params_mapzooms[0]) - 1)
79 /**************************/
82 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
83 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml );
84 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
85 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
86 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation );
87 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation );
88 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp );
89 static VikMapsLayer *maps_layer_new ( VikViewport *vvp );
90 static void maps_layer_free ( VikMapsLayer *vml );
91 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
92 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp );
93 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp );
94 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir );
95 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload );
96 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp );
97 static guint map_uniq_id_to_index ( guint uniq_id );
100 static VikLayerParamScale params_scales[] = {
101 /* min, max, step, digits (decimal places) */
102 { 0, 255, 3, 0 }, /* alpha */
105 static VikLayerParamData mode_default ( void ) { return VIK_LPD_UINT ( 19 ); } // OSM MapQuest maps
106 static VikLayerParamData directory_default ( void )
108 VikLayerParamData data;
109 data.s = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
112 static VikLayerParamData alpha_default ( void ) { return VIK_LPD_UINT ( 255 ); }
113 static VikLayerParamData mapzoom_default ( void ) { return VIK_LPD_UINT ( 0 ); }
115 VikLayerParam maps_layer_params[] = {
116 { VIK_LAYER_MAPS, "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_COMBOBOX, NULL, NULL, NULL, mode_default },
117 { VIK_LAYER_MAPS, "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, NULL, directory_default },
118 { VIK_LAYER_MAPS, "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales, NULL,
119 N_("Control the Alpha value for transparency effects"), alpha_default },
120 { VIK_LAYER_MAPS, "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL, NULL, vik_lpd_true_default },
121 { VIK_LAYER_MAPS, "adlonlymissing", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload Only Gets Missing Maps:"), VIK_LAYER_WIDGET_CHECKBUTTON, NULL, NULL,
122 N_("Using this option avoids attempting to update already acquired tiles. This can be useful if you want to restrict the network usage, without having to resort to manual control. Only applies when 'Autodownload Maps' is on."), vik_lpd_false_default },
123 { VIK_LAYER_MAPS, "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms, NULL,
124 N_("Determines the method of displaying map tiles for the current zoom level. 'Viking Zoom Level' uses the best matching level, otherwise setting a fixed value will always use map tiles of the specified value regardless of the actual zoom level."),
138 static VikToolInterface maps_tools[] = {
139 { { "MapsDownload", "vik-icon-Maps Download", N_("_Maps Download"), NULL, N_("Maps Download"), 0 },
140 (VikToolConstructorFunc) maps_layer_download_create,
144 (VikToolMouseFunc) maps_layer_download_click,
146 (VikToolMouseFunc) maps_layer_download_release,
149 GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
152 VikLayerInterface vik_maps_layer_interface = {
156 &vikmapslayer_pixbuf,
159 sizeof(maps_tools) / sizeof(maps_tools[0]),
168 (VikLayerFuncCreate) maps_layer_new,
169 (VikLayerFuncRealize) NULL,
170 (VikLayerFuncPostRead) maps_layer_post_read,
171 (VikLayerFuncFree) maps_layer_free,
173 (VikLayerFuncProperties) NULL,
174 (VikLayerFuncDraw) maps_layer_draw,
175 (VikLayerFuncChangeCoordMode) NULL,
177 (VikLayerFuncSetMenuItemsSelection) NULL,
178 (VikLayerFuncGetMenuItemsSelection) NULL,
180 (VikLayerFuncAddMenuItems) maps_layer_add_menu_items,
181 (VikLayerFuncSublayerAddMenuItems) NULL,
183 (VikLayerFuncSublayerRenameRequest) NULL,
184 (VikLayerFuncSublayerToggleVisible) NULL,
185 (VikLayerFuncSublayerTooltip) NULL,
186 (VikLayerFuncLayerTooltip) maps_layer_tooltip,
187 (VikLayerFuncLayerSelected) NULL,
189 (VikLayerFuncMarshall) maps_layer_marshall,
190 (VikLayerFuncUnmarshall) maps_layer_unmarshall,
192 (VikLayerFuncSetParam) maps_layer_set_param,
193 (VikLayerFuncGetParam) maps_layer_get_param,
195 (VikLayerFuncReadFileData) NULL,
196 (VikLayerFuncWriteFileData) NULL,
198 (VikLayerFuncDeleteItem) NULL,
199 (VikLayerFuncCutItem) NULL,
200 (VikLayerFuncCopyItem) NULL,
201 (VikLayerFuncPasteItem) NULL,
202 (VikLayerFuncFreeCopiedItem) NULL,
203 (VikLayerFuncDragDropRequest) NULL,
205 (VikLayerFuncSelectClick) NULL,
206 (VikLayerFuncSelectMove) NULL,
207 (VikLayerFuncSelectRelease) NULL,
208 (VikLayerFuncSelectedViewportMenu) NULL,
211 struct _VikMapsLayer {
217 gdouble xmapzoom, ymapzoom;
219 gboolean autodownload;
220 gboolean adl_only_missing;
221 VikCoord *last_center;
225 gint dl_tool_x, dl_tool_y;
227 GtkMenu *dl_right_click_menu;
228 VikCoord redownload_ul, redownload_br; /* right click menu only */
229 VikViewport *redownload_vvp;
231 gboolean license_notice_shown; // FALSE for new maps only, otherwise
232 // TRUE for saved maps & other layer changes as we don't need to show it again
235 enum { REDOWNLOAD_NONE = 0, /* download only missing maps */
236 REDOWNLOAD_BAD, /* download missing and bad maps */
237 REDOWNLOAD_NEW, /* download missing maps that are newer on server only */
238 REDOWNLOAD_ALL, /* download all maps */
239 DOWNLOAD_OR_REFRESH }; /* download missing maps and refresh cache */
241 static VikLayerParam prefs[] = {
242 { VIK_LAYER_NUM_TYPES, VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Default maplayer directory:"), VIK_LAYER_WIDGET_FOLDERENTRY, NULL, NULL, N_("Choose a directory to store cached Map tiles for this layer") },
245 void maps_layer_init ()
247 VikLayerParamData tmp;
248 tmp.s = maps_layer_default_dir();
249 a_preferences_register(prefs, tmp, VIKING_PREFERENCES_GROUP_KEY);
252 /****************************************/
253 /******** MAPS LAYER TYPES **************/
254 /****************************************/
256 int _get_index_for_id ( guint id )
259 while (params_maptypes_ids[index] != 0)
261 if (params_maptypes_ids[index] == id)
268 void _add_map_source ( guint id, const char *label, VikMapSource *map )
272 len = g_strv_length (params_maptypes);
274 params_maptypes = g_realloc (params_maptypes, (len+2)*sizeof(gchar*));
275 params_maptypes[len] = g_strdup (label);
276 params_maptypes[len+1] = NULL;
279 params_maptypes_ids = g_realloc (params_maptypes_ids, (len+2)*sizeof(guint));
280 params_maptypes_ids[len] = id;
281 params_maptypes_ids[len+1] = 0;
283 /* We have to clone */
284 VikMapSource *clone = VIK_MAP_SOURCE(g_object_ref(map));
285 /* Register the clone in the list */
286 __map_types = g_list_append(__map_types, clone);
289 We have to ensure the mode LayerParam references the up-to-date
293 memcpy(&maps_layer_params[0].widget_data, ¶ms_maptypes, sizeof(gpointer));
294 memcpy(&maps_layer_params[0].extra_widget_data, ¶ms_maptypes_ids, sizeof(gpointer));
296 maps_layer_params[0].widget_data = params_maptypes;
297 maps_layer_params[0].extra_widget_data = params_maptypes_ids;
300 void _update_map_source ( const char *label, VikMapSource *map, int index )
302 GList *item = g_list_nth (__map_types, index);
303 g_object_unref (item->data);
304 item->data = g_object_ref (map);
305 /* Change previous data */
306 g_free (params_maptypes[index]);
307 params_maptypes[index] = g_strdup (label);
311 * maps_layer_register_map_source:
312 * @map: the new VikMapSource
314 * Register a new VikMapSource.
315 * Override existing one (equality of id).
317 void maps_layer_register_map_source ( VikMapSource *map )
319 g_assert(map != NULL);
321 guint id = vik_map_source_get_uniq_id(map);
322 const char *label = vik_map_source_get_label(map);
323 g_assert(label != NULL);
325 int previous = map_uniq_id_to_index (id);
326 if (previous != NUM_MAP_TYPES)
328 _update_map_source (label, map, previous);
332 _add_map_source (id, label, map);
336 #define MAPS_LAYER_NTH_LABEL(n) (params_maptypes[n])
337 #define MAPS_LAYER_NTH_ID(n) (params_maptypes_ids[n])
338 #define MAPS_LAYER_NTH_TYPE(n) (VIK_MAP_SOURCE(g_list_nth_data(__map_types, (n))))
340 gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
342 return(vml->maptype);
345 gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
347 return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
350 /****************************************/
351 /******** CACHE DIR STUFF ***************/
352 /****************************************/
354 #define DIRECTDIRACCESS "%s%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d%s"
355 #define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
356 #define MAPS_CACHE_DIR maps_layer_default_dir()
360 #define GLOBAL_MAPS_DIR "C:\\VIKING-MAPS\\"
361 #define LOCAL_MAPS_DIR "VIKING-MAPS"
362 #elif defined __APPLE__
364 #define GLOBAL_MAPS_DIR "/Library/cache/Viking/maps/"
365 #define LOCAL_MAPS_DIR "/Library/Application Support/Viking/viking-maps"
368 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
369 #define LOCAL_MAPS_DIR ".viking-maps"
372 gchar *maps_layer_default_dir ()
374 static gchar *defaultdir = NULL;
377 /* Thanks to Mike Davison for the $VIKING_MAPS usage */
378 const gchar *mapdir = g_getenv("VIKING_MAPS");
380 defaultdir = g_strdup ( mapdir );
381 } else if ( g_access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
382 defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
384 const gchar *home = g_get_home_dir();
385 if (!home || g_access(home, W_OK))
386 home = g_get_home_dir ();
388 defaultdir = g_build_filename ( home, LOCAL_MAPS_DIR, NULL );
390 defaultdir = g_strdup ( LOCAL_MAPS_DIR );
392 if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
394 /* Add the separator at the end */
395 gchar *tmp = defaultdir;
396 defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
399 g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
404 static void maps_layer_mkdir_if_default_dir ( VikMapsLayer *vml )
406 if ( vml->cache_dir && strcmp ( vml->cache_dir, MAPS_CACHE_DIR ) == 0 && g_file_test ( vml->cache_dir, G_FILE_TEST_EXISTS ) == FALSE )
408 g_mkdir ( vml->cache_dir, 0777 );
412 static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
415 g_assert ( vml != NULL);
416 g_free ( vml->cache_dir );
417 vml->cache_dir = NULL;
419 if ( dir == NULL || dir[0] == '\0' )
421 if ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir") )
422 vml->cache_dir = g_strdup ( a_preferences_get(VIKING_PREFERENCES_NAMESPACE "maplayer_default_dir")->s );
427 if ( dir[len-1] != G_DIR_SEPARATOR )
429 vml->cache_dir = g_malloc ( len+2 );
430 strncpy ( vml->cache_dir, dir, len );
431 vml->cache_dir[len] = G_DIR_SEPARATOR;
432 vml->cache_dir[len+1] = '\0';
435 vml->cache_dir = g_strdup ( dir );
437 maps_layer_mkdir_if_default_dir ( vml );
440 /****************************************/
441 /******** GOBJECT STUFF *****************/
442 /****************************************/
444 GType vik_maps_layer_get_type ()
446 static GType vml_type = 0;
450 static const GTypeInfo vml_info =
452 sizeof (VikMapsLayerClass),
453 NULL, /* base_init */
454 NULL, /* base_finalize */
455 NULL, /* class init */
456 NULL, /* class_finalize */
457 NULL, /* class_data */
458 sizeof (VikMapsLayer),
460 NULL /* instance init */
462 vml_type = g_type_register_static ( VIK_LAYER_TYPE, "VikMapsLayer", &vml_info, 0 );
468 /****************************************/
469 /************** PARAMETERS **************/
470 /****************************************/
472 static guint map_index_to_uniq_id (guint8 index)
474 g_assert ( index < NUM_MAP_TYPES );
475 return vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(index));
478 static guint map_uniq_id_to_index ( guint uniq_id )
481 for ( i = 0; i < NUM_MAP_TYPES; i++ )
482 if ( vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(i)) == uniq_id )
484 return NUM_MAP_TYPES; /* no such thing */
487 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp, gboolean is_file_operation )
489 // When loading from a file don't need the license reminder
490 if ( is_file_operation )
491 vml->license_notice_shown = TRUE;
495 case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
496 case PARAM_MAPTYPE: {
497 gint maptype = map_uniq_id_to_index(data.u);
498 if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
499 else vml->maptype = maptype;
502 case PARAM_ALPHA: if ( data.u <= 255 ) vml->alpha = data.u; break;
503 case PARAM_AUTODOWNLOAD: vml->autodownload = data.b; break;
504 case PARAM_ONLYMISSING: vml->adl_only_missing = data.b; break;
505 case PARAM_MAPZOOM: if ( data.u < NUM_MAPZOOMS ) {
506 vml->mapzoom_id = data.u;
507 vml->xmapzoom = __mapzooms_x [data.u];
508 vml->ymapzoom = __mapzooms_y [data.u];
509 }else g_warning (_("Unknown Map Zoom")); break;
514 static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id, gboolean is_file_operation )
516 VikLayerParamData rv;
519 case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
520 case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
521 case PARAM_ALPHA: rv.u = vml->alpha; break;
522 case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
523 case PARAM_ONLYMISSING: rv.u = vml->adl_only_missing; break;
524 case PARAM_MAPZOOM: rv.u = vml->mapzoom_id; break;
529 /****************************************/
530 /****** CREATING, COPYING, FREEING ******/
531 /****************************************/
533 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
535 VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
536 vik_layer_set_type ( VIK_LAYER(vml), VIK_LAYER_MAPS );
538 vik_layer_set_defaults ( VIK_LAYER(vml), vvp );
540 vml->dl_tool_x = vml->dl_tool_y = -1;
541 vml->last_center = NULL;
542 vml->last_xmpp = 0.0;
543 vml->last_ympp = 0.0;
545 vml->dl_right_click_menu = NULL;
546 vml->license_notice_shown = FALSE;
551 static void maps_layer_free ( VikMapsLayer *vml )
553 g_free ( vml->cache_dir );
554 vml->cache_dir = NULL;
555 if ( vml->dl_right_click_menu )
556 g_object_ref_sink ( G_OBJECT(vml->dl_right_click_menu) );
557 g_free(vml->last_center);
558 vml->last_center = NULL;
561 static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
563 if (from_file != TRUE)
565 /* If this method is not called in file reading context
566 * it is called in GUI context.
567 * So, we can check if we have to inform the user about inconsistency */
568 VikViewportDrawMode vp_drawmode;
569 VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
570 VikMapSource *map = NULL;
572 vp_drawmode = vik_viewport_get_drawmode ( vp );
573 map = MAPS_LAYER_NTH_TYPE(vml->maptype);
574 if (vik_map_source_get_drawmode(map) != vp_drawmode) {
575 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vp, vik_map_source_get_drawmode(map));
576 gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
577 a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_WIDGET(vp), msg );
581 if (vik_map_source_get_license (map) != NULL) {
582 if ( ! vml->license_notice_shown ) {
583 a_dialog_license (VIK_GTK_WINDOW_FROM_WIDGET(vp), vik_map_source_get_label (map),
584 vik_map_source_get_license (map), vik_map_source_get_license_url (map) );
585 vml->license_notice_shown = TRUE;
591 static const gchar* maps_layer_tooltip ( VikMapsLayer *vml )
593 return vik_maps_layer_get_map_label ( vml );
596 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
598 vik_layer_marshall_params ( VIK_LAYER(vml), data, len );
601 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
603 VikMapsLayer *rv = maps_layer_new ( vvp );
604 vik_layer_unmarshall_params ( VIK_LAYER(rv), data, len, vvp );
608 /*********************/
609 /****** DRAWING ******/
610 /*********************/
612 static GdkPixbuf *pixbuf_set_alpha ( GdkPixbuf *pixbuf, guint8 alpha )
615 gint width, height, iii, jjj;
617 if ( ! gdk_pixbuf_get_has_alpha ( pixbuf ) )
619 GdkPixbuf *tmp = gdk_pixbuf_add_alpha(pixbuf,FALSE,0,0,0);
620 g_object_unref(G_OBJECT(pixbuf));
624 pixels = gdk_pixbuf_get_pixels(pixbuf);
625 width = gdk_pixbuf_get_width(pixbuf);
626 height = gdk_pixbuf_get_height(pixbuf);
628 /* r,g,b,a,r,g,b,a.... */
629 for (iii = 0; iii < width; iii++) for (jjj = 0; jjj < height; jjj++)
637 static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdouble yshrinkfactor )
640 guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
641 tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
642 g_object_unref ( G_OBJECT(pixbuf) );
646 static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord, gchar *filename_buf, gint buf_len, gdouble xshrinkfactor, gdouble yshrinkfactor )
651 pixbuf = a_mapcache_get ( mapcoord->x, mapcoord->y, mapcoord->z,
652 mode, mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
655 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
656 g_snprintf ( filename_buf, buf_len, DIRECTDIRACCESS,
657 vml->cache_dir, (17 - mapcoord->scale), mapcoord->x, mapcoord->y, ".png" );
659 g_snprintf ( filename_buf, buf_len, DIRSTRUCTURE,
660 vml->cache_dir, mode,
661 mapcoord->scale, mapcoord->z, mapcoord->x, mapcoord->y );
663 if ( g_file_test ( filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
666 pixbuf = gdk_pixbuf_new_from_file ( filename_buf, &gx );
668 /* free the pixbuf on error */
671 if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
672 g_warning ( _("Couldn't open image file: %s"), gx->message );
676 g_object_unref ( G_OBJECT(pixbuf) );
679 if ( vml->alpha < 255 )
680 pixbuf = pixbuf_set_alpha ( pixbuf, vml->alpha );
681 if ( xshrinkfactor != 1.0 || yshrinkfactor != 1.0 )
682 pixbuf = pixbuf_shrink ( pixbuf, xshrinkfactor, yshrinkfactor );
684 a_mapcache_add ( pixbuf, mapcoord->x, mapcoord->y,
685 mapcoord->z, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(vml->maptype)),
686 mapcoord->scale, vml->alpha, xshrinkfactor, yshrinkfactor );
693 gboolean should_start_autodownload(VikMapsLayer *vml, VikViewport *vvp)
695 const VikCoord *center = vik_viewport_get_center ( vvp );
697 if (vik_window_get_pan_move (VIK_WINDOW(VIK_GTK_WINDOW_FROM_WIDGET(GTK_WIDGET(vvp)))))
698 /* D'n'D pan in action: do not download */
701 if (vml->last_center == NULL) {
702 VikCoord *new_center = g_malloc(sizeof(VikCoord));
703 *new_center = *center;
704 vml->last_center = new_center;
705 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
706 vml->last_ympp = vik_viewport_get_ympp(vvp);
710 /* TODO: perhaps vik_coord_diff() */
711 if (vik_coord_equals(vml->last_center, center)
712 && (vml->last_xmpp == vik_viewport_get_xmpp(vvp))
713 && (vml->last_ympp == vik_viewport_get_ympp(vvp)))
716 *(vml->last_center) = *center;
717 vml->last_xmpp = vik_viewport_get_xmpp(vvp);
718 vml->last_ympp = vik_viewport_get_ympp(vvp);
722 static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br )
725 gdouble xzoom = vik_viewport_get_xmpp ( vvp );
726 gdouble yzoom = vik_viewport_get_ympp ( vvp );
727 gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
728 gboolean existence_only = FALSE;
730 if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
731 xshrinkfactor = vml->xmapzoom / xzoom;
732 yshrinkfactor = vml->ymapzoom / yzoom;
733 xzoom = vml->xmapzoom;
734 yzoom = vml->xmapzoom;
735 if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
736 yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
737 if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
738 existence_only = TRUE;
740 g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
747 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
748 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm ) &&
749 vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) ) {
753 gint xmin = MIN(ulm.x, brm.x), xmax = MAX(ulm.x, brm.x);
754 gint ymin = MIN(ulm.y, brm.y), ymax = MAX(ulm.y, brm.y);
755 gint mode = vik_map_source_get_uniq_id(map);
758 gint xx, yy, width, height;
761 guint max_path_len = strlen(vml->cache_dir) + 40;
762 gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
764 if ( (!existence_only) && vml->autodownload && should_start_autodownload(vml, vvp)) {
765 g_debug("%s: Starting autodownload", __FUNCTION__);
766 if ( !vml->adl_only_missing && vik_map_source_supports_download_only_new (map) )
767 // Try to download newer tiles
768 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
770 // Download only missing tiles
771 start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
774 if ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
775 for ( x = xmin; x <= xmax; x++ ) {
776 for ( y = ymin; y <= ymax; y++ ) {
779 pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
781 width = gdk_pixbuf_get_width ( pixbuf );
782 height = gdk_pixbuf_get_height ( pixbuf );
784 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
785 vik_viewport_coord_to_screen ( vvp, &coord, &xx, &yy );
789 vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, width, height );
793 } else { /* tilesize is known, don't have to keep converting coords */
794 gdouble tilesize_x = vik_map_source_get_tilesize_x(map) * xshrinkfactor;
795 gdouble tilesize_y = vik_map_source_get_tilesize_y(map) * yshrinkfactor;
796 /* ceiled so tiles will be maximum size in the case of funky shrinkfactor */
797 gint tilesize_x_ceil = ceil ( tilesize_x );
798 gint tilesize_y_ceil = ceil ( tilesize_y );
799 gint8 xinc = (ulm.x == xmin) ? 1 : -1;
800 gint8 yinc = (ulm.y == ymin) ? 1 : -1;
801 gdouble xx, yy; gint xx_tmp, yy_tmp;
802 gint base_yy, xend, yend;
804 xend = (xinc == 1) ? (xmax+1) : (xmin-1);
805 yend = (yinc == 1) ? (ymax+1) : (ymin-1);
807 vik_map_source_mapcoord_to_center_coord ( map, &ulm, &coord );
808 vik_viewport_coord_to_screen ( vvp, &coord, &xx_tmp, &yy_tmp );
809 xx = xx_tmp; yy = yy_tmp;
810 /* above trick so xx,yy doubles. this is so shrinkfactors aren't rounded off
811 * eg if tile size 128, shrinkfactor 0.333 */
812 xx -= (tilesize_x/2);
813 base_yy = yy - (tilesize_y/2);
815 for ( x = ((xinc == 1) ? xmin : xmax); x != xend; x+=xinc ) {
817 for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
821 if ( existence_only ) {
822 if ( vik_map_source_is_direct_file_access (MAPS_LAYER_NTH_TYPE(vml->maptype)) )
823 g_snprintf ( path_buf, max_path_len, DIRECTDIRACCESS,
824 vml->cache_dir, (17 - ulm.scale), ulm.x, ulm.y, ".png" );
826 g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
827 vml->cache_dir, mode,
828 ulm.scale, ulm.z, ulm.x, ulm.y );
829 if ( g_file_test ( path_buf, G_FILE_TEST_EXISTS ) == TRUE ) {
830 GdkGC *black_gc = gtk_widget_get_style(GTK_WIDGET(vvp))->black_gc;
831 vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
835 for (scale_inc = 0; scale_inc < 4; scale_inc ++) {
836 /* try with correct then smaller zooms */
837 int scale_factor = 1 << scale_inc; /* 2^scale_inc */
839 ulm2.x = ulm.x / scale_factor;
840 ulm2.y = ulm.y / scale_factor;
841 ulm2.scale = ulm.scale + scale_inc;
842 pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
844 gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
845 gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
847 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);
849 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
854 /* retry with bigger zooms */
856 for (scale_dec = 1; scale_dec < 2; scale_dec ++) {
858 int scale_factor = 1 << scale_dec; /* 2^scale_dec */
860 ulm2.x = ulm.x * scale_factor;
861 ulm2.y = ulm.y * scale_factor;
862 ulm2.scale = ulm.scale - scale_dec;
863 for (pict_x = 0; pict_x < scale_factor; pict_x ++) {
864 for (pict_y = 0; pict_y < scale_factor; pict_y ++) {
865 MapCoord ulm3 = ulm2;
868 pixbuf = get_pixbuf ( vml, mode, &ulm3, path_buf, max_path_len, xshrinkfactor / scale_factor, yshrinkfactor / scale_factor );
872 gint dest_x = xx + pict_x * (tilesize_x_ceil / scale_factor);
873 gint dest_y = yy + pict_y * (tilesize_y_ceil / scale_factor);
874 vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, dest_x, dest_y, tilesize_x_ceil / scale_factor, tilesize_y_ceil / scale_factor );
892 static void maps_layer_draw ( VikMapsLayer *vml, VikViewport *vvp )
894 if ( vik_map_source_get_drawmode(MAPS_LAYER_NTH_TYPE(vml->maptype)) == vik_viewport_get_drawmode ( vvp ) )
899 gdouble level = vik_viewport_get_zoom ( vvp );
901 vik_viewport_get_min_max_lat_lon ( vvp, &bbox.south, &bbox.north, &bbox.west, &bbox.east );
902 vik_map_source_get_copyright ( MAPS_LAYER_NTH_TYPE(vml->maptype), bbox, level, vik_viewport_add_copyright, vvp );
905 const GdkPixbuf *logo = vik_map_source_get_logo ( MAPS_LAYER_NTH_TYPE(vml->maptype) );
906 vik_viewport_add_logo ( vvp, logo );
908 /* get corner coords */
909 if ( vik_viewport_get_coord_mode ( vvp ) == VIK_COORD_UTM && ! vik_viewport_is_one_zone ( vvp ) ) {
910 /* UTM multi-zone stuff by Kit Transue */
911 gchar leftmost_zone, rightmost_zone, i;
912 leftmost_zone = vik_viewport_leftmost_zone( vvp );
913 rightmost_zone = vik_viewport_rightmost_zone( vvp );
914 for ( i = leftmost_zone; i <= rightmost_zone; ++i ) {
915 vik_viewport_corners_for_zonen ( vvp, i, &ul, &br );
916 maps_layer_draw_section ( vml, vvp, &ul, &br );
920 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
921 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
923 maps_layer_draw_section ( vml, vvp, &ul, &br );
928 /*************************/
929 /****** DOWNLOADING ******/
930 /*************************/
932 /* pass along data to thread, exists even if layer is deleted. */
942 gboolean refresh_display;
945 gboolean map_layer_alive;
949 static void mdi_free ( MapDownloadInfo *mdi )
951 g_mutex_free(mdi->mutex);
952 g_free ( mdi->cache_dir );
953 mdi->cache_dir = NULL;
954 g_free ( mdi->filename_buf );
955 mdi->filename_buf = NULL;
959 static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
961 MapDownloadInfo *mdi = ptr;
962 g_mutex_lock(mdi->mutex);
963 mdi->map_layer_alive = FALSE;
964 g_mutex_unlock(mdi->mutex);
967 static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
969 void *handle = vik_map_source_download_handle_init(MAPS_LAYER_NTH_TYPE(mdi->maptype));
972 for ( x = mdi->x0; x <= mdi->xf; x++ )
974 for ( y = mdi->y0; y <= mdi->yf; y++ )
976 gboolean remove_mem_cache = FALSE;
977 gboolean need_download = FALSE;
978 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
979 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
980 mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
983 int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
985 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
989 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE ) {
990 need_download = TRUE;
991 remove_mem_cache = TRUE;
993 } else { /* in case map file already exists */
994 switch (mdi->redownload) {
995 case REDOWNLOAD_NONE:
1000 /* see if this one is bad or what */
1002 GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file ( mdi->filename_buf, &gx );
1003 if (gx || (!pixbuf)) {
1004 g_remove ( mdi->filename_buf );
1005 need_download = TRUE;
1006 remove_mem_cache = TRUE;
1007 g_error_free ( gx );
1010 g_object_unref ( pixbuf );
1015 case REDOWNLOAD_NEW:
1016 need_download = TRUE;
1017 remove_mem_cache = TRUE;
1020 case REDOWNLOAD_ALL:
1021 /* FIXME: need a better way than to erase file in case of server/network problem */
1022 g_remove ( mdi->filename_buf );
1023 need_download = TRUE;
1024 remove_mem_cache = TRUE;
1027 case DOWNLOAD_OR_REFRESH:
1028 remove_mem_cache = TRUE;
1032 g_warning ( "redownload state %d unknown\n", mdi->redownload);
1036 mdi->mapcoord.x = x; mdi->mapcoord.y = y;
1038 if (need_download) {
1039 if ( vik_map_source_download( MAPS_LAYER_NTH_TYPE(mdi->maptype), &(mdi->mapcoord), mdi->filename_buf, handle))
1043 g_mutex_lock(mdi->mutex);
1044 if (remove_mem_cache)
1045 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 );
1046 if (mdi->refresh_display && mdi->map_layer_alive) {
1047 /* TODO: check if it's on visible area */
1048 vik_layer_emit_update ( VIK_LAYER(mdi->vml) ); // NB update display from background
1050 g_mutex_unlock(mdi->mutex);
1051 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* we're temporarily between downloads */
1055 vik_map_source_download_handle_cleanup(MAPS_LAYER_NTH_TYPE(mdi->maptype), handle);
1056 g_mutex_lock(mdi->mutex);
1057 if (mdi->map_layer_alive)
1058 g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1059 g_mutex_unlock(mdi->mutex);
1063 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
1065 if ( mdi->mapcoord.x || mdi->mapcoord.y )
1067 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1068 mdi->cache_dir, vik_map_source_get_uniq_id(MAPS_LAYER_NTH_TYPE(mdi->maptype)),
1069 mdi->mapcoord.scale, mdi->mapcoord.z, mdi->mapcoord.x, mdi->mapcoord.y );
1070 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == TRUE)
1072 g_remove ( mdi->filename_buf );
1077 static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const VikCoord *ul, const VikCoord *br, gint redownload )
1079 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1080 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1082 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1084 // Don't ever attempt download on direct access
1085 if ( vik_map_source_is_direct_file_access ( map ) )
1088 if ( vik_map_source_coord_to_mapcoord ( map, ul, xzoom, yzoom, &ulm )
1089 && vik_map_source_coord_to_mapcoord ( map, br, xzoom, yzoom, &brm ) )
1091 MapDownloadInfo *mdi = g_malloc ( sizeof(MapDownloadInfo) );
1096 mdi->map_layer_alive = TRUE;
1097 mdi->mutex = g_mutex_new();
1098 mdi->refresh_display = TRUE;
1100 /* cache_dir and buffer for dest filename */
1101 mdi->cache_dir = g_strdup ( vml->cache_dir );
1102 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1103 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1104 mdi->maptype = vml->maptype;
1106 mdi->mapcoord = ulm;
1108 mdi->redownload = redownload;
1110 mdi->x0 = MIN(ulm.x, brm.x);
1111 mdi->xf = MAX(ulm.x, brm.x);
1112 mdi->y0 = MIN(ulm.y, brm.y);
1113 mdi->yf = MAX(ulm.y, brm.y);
1117 if ( mdi->redownload ) {
1118 mdi->mapstoget = (mdi->xf - mdi->x0 + 1) * (mdi->yf - mdi->y0 + 1);
1120 /* calculate how many we need */
1121 for ( a = mdi->x0; a <= mdi->xf; a++ )
1123 for ( b = mdi->y0; b <= mdi->yf; b++ )
1125 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1126 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1128 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1134 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1136 if ( mdi->mapstoget )
1138 const gchar *tmp_str;
1143 if (redownload == REDOWNLOAD_BAD)
1144 tmp_str = ngettext("Redownloading up to %d %s map...", "Redownloading up to %d %s maps...", mdi->mapstoget);
1146 tmp_str = ngettext("Redownloading %d %s map...", "Redownloading %d %s maps...", mdi->mapstoget);
1150 tmp_str = ngettext("Downloading %d %s map...", "Downloading %d %s maps...", mdi->mapstoget);
1152 tmp = g_strdup_printf ( tmp_str, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype));
1154 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1155 /* launch the thread */
1156 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1157 tmp, /* description string */
1158 (vik_thr_func) map_download_thread, /* function to call within thread */
1159 mdi, /* pass along data */
1160 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1161 (vik_thr_free_func) mdi_cancel_cleanup,
1170 void maps_layer_download_section ( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
1173 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1175 // Don't ever attempt download on direct access
1176 if ( vik_map_source_is_direct_file_access ( map ) )
1179 if (!vik_map_source_coord_to_mapcoord(map, ul, zoom, zoom, &ulm)
1180 || !vik_map_source_coord_to_mapcoord(map, br, zoom, zoom, &brm)) {
1181 g_warning("%s() coord_to_mapcoord() failed", __PRETTY_FUNCTION__);
1185 MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
1190 mdi->map_layer_alive = TRUE;
1191 mdi->mutex = g_mutex_new();
1192 mdi->refresh_display = TRUE;
1194 mdi->cache_dir = g_strdup ( vml->cache_dir );
1195 mdi->maxlen = strlen ( vml->cache_dir ) + 40;
1196 mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
1197 mdi->maptype = vml->maptype;
1199 mdi->mapcoord = ulm;
1201 mdi->redownload = REDOWNLOAD_NONE;
1203 mdi->x0 = MIN(ulm.x, brm.x);
1204 mdi->xf = MAX(ulm.x, brm.x);
1205 mdi->y0 = MIN(ulm.y, brm.y);
1206 mdi->yf = MAX(ulm.y, brm.y);
1210 for (i = mdi->x0; i <= mdi->xf; i++) {
1211 for (j = mdi->y0; j <= mdi->yf; j++) {
1212 g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
1213 vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale,
1215 if ( g_file_test ( mdi->filename_buf, G_FILE_TEST_EXISTS ) == FALSE )
1220 mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
1222 if (mdi->mapstoget) {
1225 fmt = ngettext("Downloading %d %s map...",
1226 "Downloading %d %s maps...",
1228 tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
1230 g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
1231 /* launch the thread */
1232 a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
1233 tmp, /* description string */
1234 (vik_thr_func) map_download_thread, /* function to call within thread */
1235 mdi, /* pass along data */
1236 (vik_thr_free_func) mdi_free, /* function to free pass along data */
1237 (vik_thr_free_func) mdi_cancel_cleanup,
1245 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
1247 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
1250 static void maps_layer_redownload_all ( VikMapsLayer *vml )
1252 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
1255 static void maps_layer_redownload_new ( VikMapsLayer *vml )
1257 start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
1261 * Display a simple dialog with information about this particular map tile
1263 static void maps_layer_tile_info ( VikMapsLayer *vml )
1265 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1267 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vml->redownload_vvp );
1268 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vml->redownload_vvp );
1271 if ( !vik_map_source_coord_to_mapcoord ( map, &(vml->redownload_ul), xzoom, yzoom, &ulm ) )
1274 gchar *filename = NULL;
1275 gchar *message = NULL;
1276 gchar *source = NULL;
1278 if ( vik_map_source_is_direct_file_access ( map ) ) {
1279 filename = g_strdup_printf ( DIRECTDIRACCESS, vml->cache_dir, ulm.scale, ulm.x, ulm.y, ".png" );
1280 source = g_strconcat ( "file://", filename, NULL );
1283 filename = g_strdup_printf ( DIRSTRUCTURE, vml->cache_dir, vik_map_source_get_uniq_id(map), ulm.scale, ulm.z, ulm.x, ulm.y );
1284 source = g_strdup_printf ( "http://%s%s",
1285 vik_map_source_default_get_hostname ( VIK_MAP_SOURCE_DEFAULT(map) ),
1286 vik_map_source_default_get_uri ( VIK_MAP_SOURCE_DEFAULT(map), &ulm ) );
1289 if ( g_file_test ( filename, G_FILE_TEST_EXISTS ) ) {
1291 // Get some timestamp information of the tile
1292 struct stat stat_buf;
1293 if ( g_stat ( filename, &stat_buf ) == 0 ) {
1294 time_t file_time = stat_buf.st_mtime;
1295 #if GLIB_CHECK_VERSION(2,26,0)
1296 GDateTime* gdt = g_date_time_new_from_unix_utc ( file_time );
1297 gchar *time = g_date_time_format ( gdt, "%c" );
1300 strftime(time, 20, "%Y-%m-%d %H:%M:%S", localtime(&file_time));
1302 message = g_strdup_printf ( _("\nSource: %s\n\nTile File: %s\nTile File Timestamp: %s"), source, filename, time );
1304 #if GLIB_CHECK_VERSION(2,26,0)
1306 g_date_time_unref ( gdt);
1311 message = g_strdup_printf ( _("Source: %s\n\nNo Tile File!"), source );
1314 a_dialog_info_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), message );
1318 g_free ( filename );
1321 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1323 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1325 if ( vml->dl_tool_x != -1 && vml->dl_tool_y != -1 )
1327 if ( event->button == 1 )
1330 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 );
1331 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 );
1332 start_download_thread ( vml, vvp, &ul, &br, DOWNLOAD_OR_REFRESH );
1333 vml->dl_tool_x = vml->dl_tool_y = -1;
1338 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) );
1339 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) );
1341 vml->redownload_vvp = vvp;
1343 vml->dl_tool_x = vml->dl_tool_y = -1;
1345 if ( ! vml->dl_right_click_menu ) {
1347 vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
1349 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _Bad Map(s)") );
1350 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
1351 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1353 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _New Map(s)") );
1354 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), vml );
1355 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1357 item = gtk_menu_item_new_with_mnemonic ( _("Redownload _All Map(s)") );
1358 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
1359 gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
1361 item = gtk_image_menu_item_new_with_mnemonic ( _("_Show Tile Information") );
1362 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) );
1363 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_tile_info), vml );
1364 gtk_menu_shell_append (GTK_MENU_SHELL(vml->dl_right_click_menu), item);
1367 gtk_menu_popup ( vml->dl_right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time );
1368 gtk_widget_show_all ( GTK_WIDGET(vml->dl_right_click_menu) );
1374 static gpointer maps_layer_download_create ( VikWindow *vw, VikViewport *vvp)
1379 static gboolean maps_layer_download_click ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
1382 if (!vml || vml->vl.type != VIK_LAYER_MAPS)
1384 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1385 if ( vik_map_source_get_drawmode(map) == vik_viewport_get_drawmode ( vvp ) &&
1386 vik_map_source_coord_to_mapcoord ( map, vik_viewport_get_center ( vvp ),
1387 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1388 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1390 vml->dl_tool_x = event->x, vml->dl_tool_y = event->y;
1397 if ( __map_types[vml->maptype].drawmode == vik_viewport_get_drawmode ( vvp ) )
1401 vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord );
1402 if ( __map_types[vml->maptype].coord_to_mapcoord ( &coord,
1403 vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp ),
1404 vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp ),
1406 gchar *filename_buf = g_strdup_printf ( DIRSTRUCTURE,
1407 vml->cache_dir, __map_types[vml->maptype].uniq_id,
1408 mapcoord.scale, mapcoord.z, mapcoord.x, mapcoord.y );
1410 __map_types[vml->maptype].download ( &mapcoord, filename_buf );
1411 g_free ( filename_buf );
1412 vik_layer_emit_update ( VIK_LAYER(vml) );
1420 static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
1422 VikMapsLayer *vml = vml_vvp[0];
1423 VikViewport *vvp = vml_vvp[1];
1424 VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
1426 gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
1427 gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
1432 vik_viewport_screen_to_coord ( vvp, 0, 0, &ul );
1433 vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
1435 VikMapSource *map = MAPS_LAYER_NTH_TYPE(vml->maptype);
1436 if ( vik_map_source_get_drawmode(map) == vp_drawmode &&
1437 vik_map_source_coord_to_mapcoord ( map, &ul, xzoom, yzoom, &ulm ) &&
1438 vik_map_source_coord_to_mapcoord ( map, &br, xzoom, yzoom, &brm ) )
1439 start_download_thread ( vml, vvp, &ul, &br, redownload );
1440 else if (vik_map_source_get_drawmode(map) != vp_drawmode) {
1441 const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, vik_map_source_get_drawmode(map));
1442 gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
1443 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
1447 a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
1451 static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
1453 download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
1456 static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
1458 download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
1461 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
1463 download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
1466 static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLayersPanel *vlp )
1468 static gpointer pass_along[2];
1470 pass_along[0] = vml;
1471 pass_along[1] = vik_layers_panel_get_viewport( VIK_LAYERS_PANEL(vlp) );
1473 item = gtk_menu_item_new();
1474 gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
1475 gtk_widget_show ( item );
1477 /* Now with icons */
1478 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _Missing Onscreen Maps") );
1479 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_MENU) );
1480 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
1481 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1482 gtk_widget_show ( item );
1484 if ( vik_map_source_supports_download_only_new (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
1485 item = gtk_image_menu_item_new_with_mnemonic ( _("Download _New Onscreen Maps") );
1486 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REDO, GTK_ICON_SIZE_MENU) );
1487 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
1488 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1489 gtk_widget_show ( item );
1492 item = gtk_image_menu_item_new_with_mnemonic ( _("Reload _All Onscreen Maps") );
1493 gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_REFRESH, GTK_ICON_SIZE_MENU) );
1494 g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
1495 gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
1496 gtk_widget_show ( item );
1500 * Enable downloading maps of the current screen area either 'new' or 'everything'
1502 void vik_maps_layer_download ( VikMapsLayer *vml, VikViewport *vvp, gboolean only_new )
1507 static gpointer pass_along[2];
1508 pass_along[0] = vml;
1509 pass_along[1] = vvp;
1512 // Get only new maps
1513 maps_layer_download_new_onscreen_maps ( pass_along );
1515 // Redownload everything
1516 maps_layer_redownload_all_onscreen_maps ( pass_along );