]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikmapslayer.c
Marking translatable strings.
[andy/viking.git] / src / vikmapslayer.c
index 2a23e612f693de237cc895ac9e704af41696cba5..a9cd76a0cce2adb89b0ec9920ef17bd26e8bb2ac 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #define MAX_SHRINKFACTOR 8.0000001 /* zoom 1 viewing 8-tiles */
 #define MIN_SHRINKFACTOR 0.0312499 /* zoom 32 viewing 1-tiles */
 
+#define REAL_MIN_SHRINKFACTOR 0.0039062499 /* if shrinkfactor is between MAX and REAL_MAX, will only check for existence */
+
 #include <gtk/gtk.h>
 #include <gdk-pixbuf/gdk-pixdata.h>
+#include <glib/gi18n.h>
+
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
@@ -56,6 +64,8 @@
 #include "mapcoord.h"
 #include "terraserver.h"
 
+#include "icons/icons.h"
+
 /****** MAP TYPES ******/
 
 static GList *__map_types = NULL;
@@ -70,7 +80,7 @@ static GList *params_maptypes_ids = NULL;
 
 /******** MAPZOOMS *********/
 
-static gchar *params_mapzooms[] = { "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 };
+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 };
 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 };
 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 };
 
@@ -79,7 +89,7 @@ static gdouble __mapzooms_y[] = { 0.0, 0.25, 1.0, 2.0, 4.0, 8.0, 16.0, 32.0, 64.
 /**************************/
 
 
-static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp );
+static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file);
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len );
 static VikMapsLayer *maps_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
 static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerParamData data, VikViewport *vvp );
@@ -101,22 +111,23 @@ static VikLayerParamScale params_scales[] = {
 };
 
 VikLayerParam maps_layer_params[] = {
-  { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Map Type:", VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
-  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, "Maps Directory (Optional):", VIK_LAYER_WIDGET_FILEENTRY },
-  { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Alpha:", VIK_LAYER_WIDGET_HSCALE, params_scales },
-  { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, "Autodownload maps:", VIK_LAYER_WIDGET_CHECKBUTTON },
-  { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, "Zoom Level:", VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
+  { "mode", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Map Type:"), VIK_LAYER_WIDGET_RADIOGROUP, NULL, NULL },
+  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory (Optional):"), VIK_LAYER_WIDGET_FILEENTRY },
+  { "alpha", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Alpha:"), VIK_LAYER_WIDGET_HSCALE, params_scales },
+  { "autodownload", VIK_LAYER_PARAM_BOOLEAN, VIK_LAYER_GROUP_NONE, N_("Autodownload maps:"), VIK_LAYER_WIDGET_CHECKBUTTON },
+  { "mapzoom", VIK_LAYER_PARAM_UINT, VIK_LAYER_GROUP_NONE, N_("Zoom Level:"), VIK_LAYER_WIDGET_COMBOBOX, params_mapzooms },
 };
 
 enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_MAPZOOM, NUM_PARAMS };
 
 static VikToolInterface maps_tools[] = {
-  { "Maps Download", (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
-    (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release },
+  { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
+    (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
+    (VikToolKeyFunc) NULL, &cursor_mapdl },
 };
 
 VikLayerInterface vik_maps_layer_interface = {
-  "Map",
+  N_("Map"),
   &mapslayer_pixbuf,
 
   maps_tools,
@@ -131,7 +142,7 @@ VikLayerInterface vik_maps_layer_interface = {
 
   (VikLayerFuncCreate)                  maps_layer_new,
   (VikLayerFuncRealize)                 NULL,
-  (VikLayerFuncPostRead)                NULL,
+                                        maps_layer_post_read,
   (VikLayerFuncFree)                    maps_layer_free,
 
   (VikLayerFuncProperties)              NULL,
@@ -147,7 +158,6 @@ VikLayerInterface vik_maps_layer_interface = {
   (VikLayerFuncSublayerRenameRequest)   NULL,
   (VikLayerFuncSublayerToggleVisible)   NULL,
 
-  (VikLayerFuncCopy)                    maps_layer_copy,
   (VikLayerFuncMarshall)               maps_layer_marshall,
   (VikLayerFuncUnmarshall)             maps_layer_unmarshall,
 
@@ -224,46 +234,58 @@ void maps_layer_register_type ( const char *label, guint id, VikMapsLayer_MapTyp
 #define MAPS_LAYER_NTH_ID(n) ((guint)g_list_nth_data(params_maptypes_ids, (n)))
 #define MAPS_LAYER_NTH_TYPE(n) ((VikMapsLayer_MapType*)g_list_nth_data(__map_types, (n)))
 
+gint vik_maps_layer_get_map_type(VikMapsLayer *vml)
+{
+  return(vml->maptype);
+}
+
+gchar *vik_maps_layer_get_map_label(VikMapsLayer *vml)
+{
+  return(g_strdup(MAPS_LAYER_NTH_LABEL(vml->maptype)));
+}
+
 /****************************************/
 /******** CACHE DIR STUFF ***************/
 /****************************************/
 
+#define DIRSTRUCTURE "%st%ds%dz%d" G_DIR_SEPARATOR_S "%d" G_DIR_SEPARATOR_S "%d"
 #ifdef WINDOWS
 #define MAPS_CACHE_DIR "C:\\VIKING-MAPS\\"
-#define DIRSTRUCTURE "%st%ds%dz%d\\%d\\%d"
 #else /* POSIX */
 
 #include <stdlib.h>
 
 #define MAPS_CACHE_DIR maps_layer_default_dir()
 #define GLOBAL_MAPS_DIR "/var/cache/maps/"
-#define DIRSTRUCTURE "%st%ds%dz%d/%d/%d"
 
-static gchar *maps_layer_default_dir ()
+gchar *maps_layer_default_dir ()
 {
-  static gchar defaultdir[512];
-  static gboolean already_run = 0;
-  if ( ! already_run )
+  static gchar *defaultdir = NULL;
+  if ( ! defaultdir )
   {
     /* Thanks to Mike Davison for the $VIKING_MAPS usage */
-    gchar *mapdir = getenv("VIKING_MAPS");
-    if ( mapdir && strlen(mapdir) < 497 ) {
-      strcpy ( defaultdir, mapdir );
+    const gchar *mapdir = g_getenv("VIKING_MAPS");
+    if ( mapdir ) {
+      defaultdir = g_strdup ( mapdir );
     } else if ( access ( GLOBAL_MAPS_DIR, W_OK ) == 0 ) {
-      strcpy ( defaultdir, GLOBAL_MAPS_DIR );
+      defaultdir = g_strdup ( GLOBAL_MAPS_DIR );
     } else {
-      gchar *home = getenv("HOME");
-      if ( home && strlen(home) < 497 )
-      {
-        strcpy ( defaultdir, home );
-        strcat ( defaultdir, "/.viking-maps/" );
-      }
+      const gchar *home = g_getenv("HOME");
+      if (!home || access(home, W_OK))
+        home = g_get_home_dir ();
+      if ( home )
+        defaultdir = g_build_filename ( home, ".viking-maps", NULL );
       else
-      {
-        strcpy ( defaultdir, ".viking-maps/" );
-      }
+        defaultdir = g_strdup ( ".viking-maps" );
+    }
+    if (defaultdir && (defaultdir[strlen(defaultdir)-1] != G_DIR_SEPARATOR))
+    {
+      /* Add the separator at the end */
+      gchar *tmp = defaultdir;
+      defaultdir = g_strconcat(tmp, G_DIR_SEPARATOR_S, NULL);
+      g_free(tmp);
     }
-    already_run = 1;
+    g_debug("%s: defaultdir=%s", __FUNCTION__, defaultdir);
   }
   return defaultdir;
 }
@@ -286,19 +308,19 @@ static void maps_layer_set_cache_dir ( VikMapsLayer *vml, const gchar *dir )
 {
   guint len;
   g_assert ( vml != NULL);
-  if ( vml->cache_dir )
-    g_free ( vml->cache_dir );
+  g_free ( vml->cache_dir );
+  vml->cache_dir = NULL;
 
   if ( dir == NULL || dir[0] == '\0' )
     vml->cache_dir = g_strdup ( MAPS_CACHE_DIR );
   else
   {
     len = strlen(dir);
-    if ( dir[len-1] != VIKING_FILE_SEP )
+    if ( dir[len-1] != G_DIR_SEPARATOR )
     {
       vml->cache_dir = g_malloc ( len+2 );
       strncpy ( vml->cache_dir, dir, len );
-      vml->cache_dir[len] = VIKING_FILE_SEP;
+      vml->cache_dir[len] = G_DIR_SEPARATOR;
       vml->cache_dir[len+1] = '\0';
     }
     else
@@ -361,7 +383,7 @@ static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerPa
     case PARAM_CACHE_DIR: maps_layer_set_cache_dir ( vml, data.s ); break;
     case PARAM_MAPTYPE: {
       gint maptype = map_uniq_id_to_index(data.u);
-      if ( maptype == NUM_MAP_TYPES ) g_warning("Unknown map type");
+      if ( maptype == NUM_MAP_TYPES ) g_warning(_("Unknown map type"));
       else vml->maptype = maptype;
       break;
     }
@@ -371,7 +393,7 @@ static gboolean maps_layer_set_param ( VikMapsLayer *vml, guint16 id, VikLayerPa
                           vml->mapzoom_id = data.u;
                           vml->xmapzoom = __mapzooms_x [data.u];
                           vml->ymapzoom = __mapzooms_y [data.u];
-                        }else g_warning ("Unknown Map Zoom"); break;
+                        }else g_warning (_("Unknown Map Zoom")); break;
   }
   return TRUE;
 }
@@ -396,9 +418,11 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
 
 static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
 {
+  int idx;
   VikMapsLayer *vml = VIK_MAPS_LAYER ( g_object_new ( VIK_MAPS_LAYER_TYPE, NULL ) );
   vik_layer_init ( VIK_LAYER(vml), VIK_LAYER_MAPS );
-  vml->maptype = 0;
+  idx = map_uniq_id_to_index(7); /* 7 is id for google maps */
+    vml->maptype = (idx < NUM_MAP_TYPES) ? idx : 0;
   vml->alpha = 255;
   vml->mapzoom_id = 0;
   vml->dl_tool_x = vml->dl_tool_y = -1;
@@ -415,21 +439,34 @@ static VikMapsLayer *maps_layer_new ( VikViewport *vvp )
 
 static void maps_layer_free ( VikMapsLayer *vml )
 {
-  if ( vml->cache_dir )
-    g_free ( vml->cache_dir );
+  g_free ( vml->cache_dir );
+  vml->cache_dir = NULL;
   if ( vml->dl_right_click_menu )
     gtk_object_sink ( GTK_OBJECT(vml->dl_right_click_menu) );
-  if (vml->last_center)
-    g_free(vml->last_center);
+  g_free(vml->last_center);
+  vml->last_center = NULL;
 }
 
-static VikMapsLayer *maps_layer_copy ( VikMapsLayer *vml, VikViewport *vvp )
+static void maps_layer_post_read (VikLayer *vl, VikViewport *vp, gboolean from_file)
 {
-  VikMapsLayer *rv = maps_layer_new ( vvp );
-  *rv = *vml;
-  rv->cache_dir = g_strdup(rv->cache_dir);
-  VIK_LAYER(rv)->name = NULL;
-  return rv;
+  if (from_file != TRUE)
+  {
+    /* If this method is not called in file reading context
+     * it is called in GUI context.
+     * So, we can check if we have to inform the user about inconsistency */
+    VikViewportDrawMode vp_drawmode;
+    VikMapsLayer *vml = VIK_MAPS_LAYER(vl);
+    VikMapsLayer_MapType *map_type = NULL;
+    vp_drawmode = vik_viewport_get_drawmode ( VIK_VIEWPORT(vp) );
+    map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
+    if (map_type->drawmode != vp_drawmode) {
+      const gchar *drawmode_name = vik_viewport_get_drawmode_name (VIK_VIEWPORT(vp), map_type->drawmode);
+      gchar *msg = g_strdup_printf(_("New map cannot be displayed in the current drawmode.\nSelect \"%s\" from View menu to view it."), drawmode_name);
+      a_dialog_warning_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), msg );
+      g_free(msg);
+    }
+  }
 }
 
 static void maps_layer_marshall( VikMapsLayer *vml, guint8 **data, gint *len )
@@ -502,7 +539,7 @@ static GdkPixbuf *get_pixbuf( VikMapsLayer *vml, gint mode, MapCoord *mapcoord,
       if (gx)
       {
         if ( gx->domain != GDK_PIXBUF_ERROR || gx->code != GDK_PIXBUF_ERROR_CORRUPT_IMAGE )
-          g_warning ( "Couldn't open image file: %s", gx->message );
+          g_warning ( _("Couldn't open image file: %s"), gx->message );
 
           g_error_free ( gx );
           if ( pixbuf )
@@ -555,16 +592,21 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
   gdouble xzoom = vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vik_viewport_get_ympp ( vvp );
   gdouble xshrinkfactor = 1.0, yshrinkfactor = 1.0;
+  gdouble existence_only = FALSE;
 
   if ( vml->xmapzoom && (vml->xmapzoom != xzoom || vml->ymapzoom != yzoom) ) {
     xshrinkfactor = vml->xmapzoom / xzoom;
     yshrinkfactor = vml->ymapzoom / yzoom;
-    if ( xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
-         yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) {
-      xzoom = vml->xmapzoom;
-      yzoom = vml->xmapzoom;
-    } else {
-      g_warning ( "Cowardly refusing to draw tiles at a shrinkfactor more than %.3f (zoomed out) or less than %.3f (zoomed in).", 1/MIN_SHRINKFACTOR, 1/MAX_SHRINKFACTOR );
+    xzoom = vml->xmapzoom;
+    yzoom = vml->xmapzoom;
+    if ( ! (xshrinkfactor > MIN_SHRINKFACTOR && xshrinkfactor < MAX_SHRINKFACTOR &&
+         yshrinkfactor > MIN_SHRINKFACTOR && yshrinkfactor < MAX_SHRINKFACTOR ) ) {
+      if ( xshrinkfactor > REAL_MIN_SHRINKFACTOR && yshrinkfactor > REAL_MIN_SHRINKFACTOR )
+        existence_only = TRUE;
+      else {
+        g_warning ( _("Cowardly refusing to draw tiles or existence of tiles beyond %d zoom out factor"), (int)( 1.0/REAL_MIN_SHRINKFACTOR));
+        return;
+      }
     }
   }
 
@@ -586,12 +628,14 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
     guint max_path_len = strlen(vml->cache_dir) + 40;
     gchar *path_buf = g_malloc ( max_path_len * sizeof(char) );
 
-    if ( vml->autodownload  && should_start_autodownload(vml, vvp)) {
-      fprintf(stderr, "DEBUG: Starting autodownload\n");
+    if ( (!existence_only) && vml->autodownload  && should_start_autodownload(vml, vvp)) {
+#ifdef DEBUG
+      fputs(stderr, "DEBUG: Starting autodownload\n");
+#endif
       start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
     }
 
-    if ( map_type->tilesize_x == 0 ) {
+    if ( map_type->tilesize_x == 0 && !existence_only ) {
       for ( x = xmin; x <= xmax; x++ ) {
         for ( y = ymin; y <= ymax; y++ ) {
           ulm.x = x;
@@ -620,6 +664,9 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
       gint8 yinc = (ulm.y == ymin) ? 1 : -1;
       gdouble xx, yy; gint xx_tmp, yy_tmp;
       gint base_yy, xend, yend;
+
+      GdkGC *black_gc = GTK_WIDGET(vvp)->style->black_gc;
+
       xend = (xinc == 1) ? (xmax+1) : (xmin-1);
       yend = (yinc == 1) ? (ymax+1) : (ymin-1);
 
@@ -636,9 +683,19 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
         for ( y = ((yinc == 1) ? ymin : ymax); y != yend; y+=yinc ) {
           ulm.x = x;
           ulm.y = y;
-          pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
-          if ( pixbuf )
-            vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+
+          if ( existence_only ) {
+            g_snprintf ( path_buf, max_path_len, DIRSTRUCTURE,
+                     vml->cache_dir, mode,
+                     ulm.scale, ulm.z, ulm.x, ulm.y );
+            if ( access ( path_buf, F_OK ) == 0 ) {
+              vik_viewport_draw_line ( vvp, black_gc, xx+tilesize_x_ceil, yy, xx, yy+tilesize_y_ceil );
+            }
+          } else {
+            pixbuf = get_pixbuf ( vml, mode, &ulm, path_buf, max_path_len, xshrinkfactor, yshrinkfactor );
+            if ( pixbuf )
+              vik_viewport_draw_pixbuf ( vvp, pixbuf, 0, 0, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+          }
 
           yy += tilesize_y;
         }
@@ -690,6 +747,7 @@ typedef struct {
   gint maxlen;
   gint mapstoget;
   gint redownload;
+  gboolean refresh_display;
   VikMapsLayer *vml;
   VikViewport *vvp;
   gboolean map_layer_alive;
@@ -700,12 +758,15 @@ static void mdi_free ( MapDownloadInfo *mdi )
 {
   g_mutex_free(mdi->mutex);
   g_free ( mdi->cache_dir );
+  mdi->cache_dir = NULL;
   g_free ( mdi->filename_buf );
+  mdi->filename_buf = NULL;
   g_free ( mdi );
 }
 
-static GWeakNotify weak_ref_cb(MapDownloadInfo *mdi, GObject * dead_vml)
+static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
 {
+  MapDownloadInfo *mdi = ptr;
   g_mutex_lock(mdi->mutex);
   mdi->map_layer_alive = FALSE;
   g_mutex_unlock(mdi->mutex);
@@ -720,14 +781,18 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
     for ( y = mdi->y0; y <= mdi->yf; y++ )
     {
       gboolean remove_mem_cache = FALSE;
+      gboolean need_download = FALSE;
       g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
                      mdi->cache_dir, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id,
                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
 
+      donemaps++;
+      a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
+
       if ( mdi->redownload == REDOWNLOAD_ALL)
         remove ( mdi->filename_buf );
 
-      else if ( mdi->redownload == REDOWNLOAD_BAD && access ( mdi->filename_buf, F_OK ) == 0 )
+      else if ( (mdi->redownload == REDOWNLOAD_BAD) && (access ( mdi->filename_buf, F_OK ) == 0) )
       {
         /* see if this one is bad or what */
         GError *gx = NULL;
@@ -742,7 +807,8 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 
       if ( access ( mdi->filename_buf, F_OK ) != 0 )
       {
-        if (( mdi->redownload != REDOWNLOAD_NONE ) ||
+        need_download = TRUE;
+        if (( mdi->redownload != REDOWNLOAD_NONE ) &&
             ( mdi->redownload != DOWNLOAD_OR_REFRESH ))
           remove_mem_cache = TRUE;
       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
@@ -750,18 +816,18 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
       } else
         continue;
 
-      donemaps++;
-      a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
-
       mdi->mapcoord.x = x; mdi->mapcoord.y = y;
-      if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
+
+      if (need_download) {
+        if ( MAPS_LAYER_NTH_TYPE(mdi->maptype)->download ( &(mdi->mapcoord), mdi->filename_buf ))
           continue;
+      }
 
       gdk_threads_enter();
       g_mutex_lock(mdi->mutex);
       if (remove_mem_cache)
           a_mapcache_remove_all_shrinkfactors ( x, y, mdi->mapcoord.z, MAPS_LAYER_NTH_TYPE(mdi->maptype)->uniq_id, mdi->mapcoord.scale );
-      if (mdi->map_layer_alive) {
+      if (mdi->refresh_display && mdi->map_layer_alive) {
         /* TODO: check if it's on visible area */
         vik_layer_emit_update ( VIK_LAYER(mdi->vml) );
       }
@@ -773,7 +839,7 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
   }
   g_mutex_lock(mdi->mutex);
   if (mdi->map_layer_alive)
-    g_object_weak_unref(VIK_LAYER(mdi->vml), weak_ref_cb, mdi);
+    g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
   g_mutex_unlock(mdi->mutex); 
 }
 
@@ -807,6 +873,7 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
     mdi->vvp = vvp;
     mdi->map_layer_alive = TRUE;
     mdi->mutex = g_mutex_new();
+    mdi->refresh_display = TRUE;
 
     /* cache_dir and buffer for dest filename */
     mdi->cache_dir = g_strdup ( vml->cache_dir );
@@ -846,9 +913,9 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
 
     if ( mdi->mapstoget )
     {
-      gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? "Redownloading" : "Downloading", redownload == REDOWNLOAD_BAD ? "up to " : "", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), (mdi->mapstoget == 1) ? "map" : "maps" );
+      gchar *tmp = g_strdup_printf ( "%s %s%d %s %s...", redownload ? _("Redownloading") : _("Downloading"), redownload == REDOWNLOAD_BAD ? _("up to ") : "", mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype), ngettext("map", "maps", mdi->mapstoget) );
 
-      g_object_weak_ref(VIK_LAYER(mdi->vml), weak_ref_cb, mdi);
+      g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
       /* launch the thread */
       a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
                             tmp,                                              /* description string */
@@ -864,6 +931,78 @@ static void start_download_thread ( VikMapsLayer *vml, VikViewport *vvp, const V
   }
 }
 
+void maps_layer_download_section_without_redraw( VikMapsLayer *vml, VikViewport *vvp, VikCoord *ul, VikCoord *br, gdouble zoom)
+{
+  MapCoord ulm, brm;
+  VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
+
+  if (!map_type->coord_to_mapcoord(ul, zoom, zoom, &ulm) 
+    || !map_type->coord_to_mapcoord(br, zoom, zoom, &brm)) {
+    g_warning("%s() coord_to_mapcoord() failed\n", __PRETTY_FUNCTION__);
+    return;
+  }
+
+  MapDownloadInfo *mdi = g_malloc(sizeof(MapDownloadInfo));
+  gint i, j;
+
+  mdi->vml = vml;
+  mdi->vvp = vvp;
+  mdi->map_layer_alive = TRUE;
+  mdi->mutex = g_mutex_new();
+  mdi->refresh_display = FALSE;
+
+  mdi->cache_dir = g_strdup ( vml->cache_dir );
+  mdi->maxlen = strlen ( vml->cache_dir ) + 40;
+  mdi->filename_buf = g_malloc ( mdi->maxlen * sizeof(gchar) );
+  mdi->maptype = vml->maptype;
+
+  mdi->mapcoord = ulm;
+
+  mdi->redownload = REDOWNLOAD_NONE;
+
+  mdi->x0 = MIN(ulm.x, brm.x);
+  mdi->xf = MAX(ulm.x, brm.x);
+  mdi->y0 = MIN(ulm.y, brm.y);
+  mdi->yf = MAX(ulm.y, brm.y);
+
+  mdi->mapstoget = 0;
+
+  for (i = mdi->x0; i <= mdi->xf; i++) {
+    for (j = mdi->y0; j <= mdi->yf; j++) {
+      g_snprintf ( mdi->filename_buf, mdi->maxlen, DIRSTRUCTURE,
+                   vml->cache_dir, map_type->uniq_id, ulm.scale,
+                   ulm.z, i, j );
+      if ( access ( mdi->filename_buf, F_OK ) != 0)
+            mdi->mapstoget++;
+    }
+  }
+
+  mdi->mapcoord.x = mdi->mapcoord.y = 0; /* for cleanup -- no current map */
+
+  if (mdi->mapstoget) {
+    gchar *tmp;
+    const gchar *fmt;
+    if (mdi->mapstoget == 1)
+      fmt = _("Downloading %d %s map...");
+    else
+      fmt = _("Downloading %d %s maps...");
+    tmp = g_strdup_printf ( fmt, mdi->mapstoget, MAPS_LAYER_NTH_LABEL(vml->maptype) );
+
+    g_object_weak_ref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
+      /* launch the thread */
+    a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vml), /* parent window */
+      tmp,                                /* description string */
+      (vik_thr_func) map_download_thread, /* function to call within thread */
+      mdi,                                /* pass along data */
+      (vik_thr_free_func) mdi_free,       /* function to free pass along data */
+      (vik_thr_free_func) mdi_cancel_cleanup,
+      mdi->mapstoget );
+    g_free ( tmp );
+  }
+  else
+    mdi_free ( mdi );
+}
+
 static void maps_layer_redownload_bad ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
@@ -901,11 +1040,11 @@ static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton
         GtkWidget *item;
         vml->dl_right_click_menu = GTK_MENU ( gtk_menu_new () );
 
-        item = gtk_menu_item_new_with_label ( "Redownload bad map(s)" );
+        item = gtk_menu_item_new_with_label ( _("Redownload bad map(s)") );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_bad), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
 
-        item = gtk_menu_item_new_with_label ( "Redownload all map(s)" );
+        item = gtk_menu_item_new_with_label ( _("Redownload all map(s)") );
         g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all), vml );
         gtk_menu_shell_append ( GTK_MENU_SHELL(vml->dl_right_click_menu), item );
       }
@@ -967,6 +1106,7 @@ static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
 {
   VikMapsLayer *vml = vml_vvp[0];
   VikViewport *vvp = vml_vvp[1];
+  VikViewportDrawMode vp_drawmode = vik_viewport_get_drawmode ( vvp );
 
   gdouble xzoom = vml->xmapzoom ? vml->xmapzoom : vik_viewport_get_xmpp ( vvp );
   gdouble yzoom = vml->ymapzoom ? vml->ymapzoom : vik_viewport_get_ympp ( vvp );
@@ -978,12 +1118,18 @@ static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
   vik_viewport_screen_to_coord ( vvp, vik_viewport_get_width(vvp), vik_viewport_get_height(vvp), &br );
 
   VikMapsLayer_MapType *map_type = MAPS_LAYER_NTH_TYPE(vml->maptype);
-  if ( map_type->drawmode == vik_viewport_get_drawmode ( vvp ) &&
+  if ( map_type->drawmode == vp_drawmode &&
        map_type->coord_to_mapcoord ( &ul, xzoom, yzoom, &ulm ) &&
        map_type->coord_to_mapcoord ( &br, xzoom, yzoom, &brm ) )
     start_download_thread ( vml, vvp, &ul, &br, redownload );
+  else if (map_type->drawmode != vp_drawmode) {
+    const gchar *drawmode_name = vik_viewport_get_drawmode_name (vvp, map_type->drawmode);
+    gchar *err = g_strdup_printf(_("Wrong drawmode for this map.\nSelect \"%s\" from View menu and try again."), _(drawmode_name));
+    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), err );
+    g_free(err);
+  }
   else
-    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), "Wrong drawmode / zoom level for this map." );
+    a_dialog_error_msg ( VIK_GTK_WINDOW_FROM_LAYER(vml), _("Wrong zoom level for this map.") );
 
 }
 
@@ -1008,12 +1154,12 @@ static void maps_layer_add_menu_items ( VikMapsLayer *vml, GtkMenu *menu, VikLay
   gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item );
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Download Onscreen Maps" );
+  item = gtk_menu_item_new_with_label ( _("Download Onscreen Maps") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
-  item = gtk_menu_item_new_with_label ( "Refresh Onscreen Tiles" );
+  item = gtk_menu_item_new_with_label ( _("Refresh Onscreen Tiles") );
   g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_all_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );