]> git.street.me.uk Git - andy/viking.git/blobdiff - src/vikmapslayer.c
Use a configure option to set the age of tiles before checking them online
[andy/viking.git] / src / vikmapslayer.c
index 89517d975f6d980aa8c3b51a8740272306eca9b6..e09d54d99d4b74535289f64dbcf2ddec07a49e6e 100644 (file)
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
+#ifdef HAVE_STRING_H
 #include <string.h>
+#endif
+#ifdef HAVE_MATH_H
 #include <math.h>
+#endif
+
 #include "globals.h"
 #include "coords.h"
 #include "vikcoord.h"
@@ -45,7 +50,6 @@
 #include "vikviewport.h"
 #include "viklayer.h"
 #include "vikmapslayer.h"
-#include "vikmapslayer_pixmap.h"
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -113,7 +117,7 @@ static VikLayerParamScale params_scales[] = {
 
 VikLayerParam maps_layer_params[] = {
   { "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 },
+  { "directory", VIK_LAYER_PARAM_STRING, VIK_LAYER_GROUP_NONE, N_("Maps Directory:"), VIK_LAYER_WIDGET_FOLDERENTRY },
   { "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 },
@@ -124,12 +128,12 @@ enum { PARAM_MAPTYPE=0, PARAM_CACHE_DIR, PARAM_ALPHA, PARAM_AUTODOWNLOAD, PARAM_
 static VikToolInterface maps_tools[] = {
   { N_("Maps Download"), (VikToolConstructorFunc) maps_layer_download_create, NULL, NULL, NULL,  
     (VikToolMouseFunc) maps_layer_download_click, NULL,  (VikToolMouseFunc) maps_layer_download_release,
-    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl },
+    (VikToolKeyFunc) NULL, GDK_CURSOR_IS_PIXMAP, &cursor_mapdl_pixbuf },
 };
 
 VikLayerInterface vik_maps_layer_interface = {
   N_("Map"),
-  &mapslayer_pixbuf,
+  &vikmapslayer_pixbuf,
 
   maps_tools,
   sizeof(maps_tools) / sizeof(maps_tools[0]),
@@ -143,7 +147,7 @@ VikLayerInterface vik_maps_layer_interface = {
 
   (VikLayerFuncCreate)                  maps_layer_new,
   (VikLayerFuncRealize)                 NULL,
-                                        maps_layer_post_read,
+  (VikLayerFuncPostRead)                maps_layer_post_read,
   (VikLayerFuncFree)                    maps_layer_free,
 
   (VikLayerFuncProperties)              NULL,
@@ -195,7 +199,11 @@ struct _VikMapsLayer {
   VikViewport *redownload_vvp;
 };
 
-enum { REDOWNLOAD_NONE = 0, REDOWNLOAD_BAD, REDOWNLOAD_ALL, DOWNLOAD_OR_REFRESH };
+enum { REDOWNLOAD_NONE = 0,    /* download only missing maps */
+       REDOWNLOAD_BAD,         /* download missing and bad maps */
+       REDOWNLOAD_NEW,         /* download missing maps that are newer on server only */
+       REDOWNLOAD_ALL,         /* download all maps */
+       DOWNLOAD_OR_REFRESH };  /* download missing maps and refresh cache */
 
 
 /****************************************/
@@ -401,7 +409,7 @@ static VikLayerParamData maps_layer_get_param ( VikMapsLayer *vml, guint16 id )
   VikLayerParamData rv;
   switch ( id )
   {
-    case PARAM_CACHE_DIR: rv.s = (vml->cache_dir && strcmp(vml->cache_dir, MAPS_CACHE_DIR) != 0) ? vml->cache_dir : ""; break;
+    case PARAM_CACHE_DIR: rv.s = vml->cache_dir ? vml->cache_dir : ""; break;
     case PARAM_MAPTYPE: rv.u = map_index_to_uniq_id ( vml->maptype ); break;
     case PARAM_ALPHA: rv.u = vml->alpha; break;
     case PARAM_AUTODOWNLOAD: rv.u = vml->autodownload; break;
@@ -512,7 +520,7 @@ static GdkPixbuf *pixbuf_shrink ( GdkPixbuf *pixbuf, gdouble xshrinkfactor, gdou
 {
   GdkPixbuf *tmp;
   guint16 width = gdk_pixbuf_get_width(pixbuf), height = gdk_pixbuf_get_height(pixbuf);
-  tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_BILINEAR);
+  tmp = gdk_pixbuf_scale_simple(pixbuf, ceil(width * xshrinkfactor), ceil(height * yshrinkfactor), GDK_INTERP_NEAREST);
   g_object_unref ( G_OBJECT(pixbuf) );
   return tmp;
 }
@@ -630,7 +638,12 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
 #ifdef DEBUG
       fputs(stderr, "DEBUG: Starting autodownload\n");
 #endif
-      start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
+      if ( map_type->options != NULL && map_type->options->check_file_server_time )
+        // Try to download newer tiles
+        start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NEW );
+      else
+        // Download only missing tiles
+        start_download_thread ( vml, vvp, ul, br, REDOWNLOAD_NONE );
     }
 
     if ( map_type->tilesize_x == 0 && !existence_only ) {
@@ -693,6 +706,24 @@ static void maps_layer_draw_section ( VikMapsLayer *vml, VikViewport *vvp, VikCo
             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 );
+            else {
+              /* retry with bigger shrinkfactor */
+              int scale_inc;
+              for (scale_inc = 1; scale_inc < 4; scale_inc ++) {
+                int scale_factor = 1 << scale_inc;  /*  2^scale_inc */
+                MapCoord ulm2 = ulm;
+                ulm2.x = ulm.x / scale_factor;
+                ulm2.y = ulm.y / scale_factor;
+                ulm2.scale = ulm.scale + scale_inc;
+                pixbuf = get_pixbuf ( vml, mode, &ulm2, path_buf, max_path_len, xshrinkfactor * scale_factor, yshrinkfactor * scale_factor );
+                if ( pixbuf ) {
+                  gint src_x = (ulm.x % scale_factor) * tilesize_x_ceil;
+                  gint src_y = (ulm.y % scale_factor) * tilesize_y_ceil;
+                  vik_viewport_draw_pixbuf ( vvp, pixbuf, src_x, src_y, xx, yy, tilesize_x_ceil, tilesize_y_ceil );
+                  break;
+                }
+              }
+            }
           }
 
           yy += tilesize_y;
@@ -770,7 +801,7 @@ static void weak_ref_cb(gpointer ptr, GObject * dead_vml)
   g_mutex_unlock(mdi->mutex);
 }
 
-static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
+static int map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
 {
   guint donemaps = 0;
   gint x, y;
@@ -785,7 +816,9 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
                      mdi->mapcoord.scale, mdi->mapcoord.z, x, y );
 
       donemaps++;
-      a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
+      int res = a_background_thread_progress ( threaddata, ((gdouble)donemaps) / mdi->mapstoget ); /* this also calls testcancel */
+      if (res != 0)
+        return -1;
 
       if ( mdi->redownload == REDOWNLOAD_ALL)
         g_remove ( mdi->filename_buf );
@@ -811,6 +844,9 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
           remove_mem_cache = TRUE;
       } else if ( mdi->redownload == DOWNLOAD_OR_REFRESH ) {
         remove_mem_cache = TRUE;
+      } else if ( mdi->redownload == REDOWNLOAD_NEW) {
+        need_download = TRUE;
+        remove_mem_cache = TRUE;
       } else
         continue;
 
@@ -839,6 +875,7 @@ static void map_download_thread ( MapDownloadInfo *mdi, gpointer threaddata )
   if (mdi->map_layer_alive)
     g_object_weak_unref(G_OBJECT(mdi->vml), weak_ref_cb, mdi);
   g_mutex_unlock(mdi->mutex); 
+  return 0;
 }
 
 static void mdi_cancel_cleanup ( MapDownloadInfo *mdi )
@@ -1018,11 +1055,17 @@ static void maps_layer_redownload_bad ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_BAD );
 }
+
 static void maps_layer_redownload_all ( VikMapsLayer *vml )
 {
   start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_ALL );
 }
 
+static void maps_layer_redownload_new ( VikMapsLayer *vml )
+{
+  start_download_thread ( vml, vml->redownload_vvp, &(vml->redownload_ul), &(vml->redownload_br), REDOWNLOAD_NEW );
+}
+
 static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton *event, VikViewport *vvp )
 {
   if (!vml || vml->vl.type != VIK_LAYER_MAPS)
@@ -1055,6 +1098,10 @@ static gboolean maps_layer_download_release ( VikMapsLayer *vml, GdkEventButton
         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 new map(s)") );
+        g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_redownload_new), 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)") );
         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 );
@@ -1144,11 +1191,16 @@ static void download_onscreen_maps ( gpointer vml_vvp[2], gint redownload )
 
 }
 
-static void maps_layer_download_onscreen_maps ( gpointer vml_vvp[2] )
+static void maps_layer_download_missing_onscreen_maps ( gpointer vml_vvp[2] )
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_NONE);
 }
 
+static void maps_layer_download_new_onscreen_maps ( gpointer vml_vvp[2] )
+{
+  download_onscreen_maps( vml_vvp, REDOWNLOAD_NEW);
+}
+
 static void maps_layer_redownload_all_onscreen_maps ( gpointer vml_vvp[2] )
 {
   download_onscreen_maps( vml_vvp, REDOWNLOAD_ALL);
@@ -1165,11 +1217,20 @@ 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") );
-  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_onscreen_maps), pass_along );
+  item = gtk_menu_item_new_with_label ( _("Download missing Onscreen Maps") );
+  g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_missing_onscreen_maps), pass_along );
   gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
   gtk_widget_show ( item );
 
+  if ( MAPS_LAYER_NTH_TYPE(vml->maptype)->options != NULL && 
+       MAPS_LAYER_NTH_TYPE(vml->maptype)->options->check_file_server_time ) {
+    item = gtk_menu_item_new_with_label ( _("Download new Onscreen Maps from server") );
+    g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(maps_layer_download_new_onscreen_maps), pass_along );
+    gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+    gtk_widget_show ( item );
+  }
+
+  /* TODO Add GTK_STOCK_REFRESH icon */
   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);