]> git.street.me.uk Git - andy/viking.git/commitdiff
Merge branch 'new-maps'
authorGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Tue, 12 Jan 2010 23:14:07 +0000 (00:14 +0100)
committerGuilhem Bonnefille <guilhem.bonnefille@gmail.com>
Tue, 12 Jan 2010 23:14:07 +0000 (00:14 +0100)
This (long lived) branch hosted a feature to allow automatic download
after a HTTP header check.

The merge is complex as Map_Type evolved to a GObject MapSource.
VikSlippyMapSource now has a new property to set the minimum age
before checking tiles.

17 files changed:
configure.ac
src/babel.c
src/curl_download.c
src/curl_download.h
src/download.c
src/download.h
src/expedia.c
src/geonamessearch.c
src/googlesearch.c
src/main.c
src/osm.c
src/vikdemlayer.c
src/vikgototool.c
src/vikmapslayer.c
src/vikmapsource.c
src/vikmapsource.h
src/vikslippymapsource.c

index aa2b07212cd4d29dec7eb4b7d7ba429fd698deca..bb8a48167d5bd5d13069ea7f44a641094525a710 100644 (file)
@@ -279,6 +279,21 @@ AC_ARG_WITH(mapcache,
 AC_DEFINE_UNQUOTED(VIK_CONFIG_MAPCACHE_SIZE, ${VIK_CONFIG_MAPCACHE_SIZE},
                    [Size of the map cache])
 
+
+AC_ARG_WITH(tileage,
+            [AC_HELP_STRING([--with-tileage],
+                            [specify the age of a tile before checking it (default is 30 s)])],
+            [if test "x$withval" = "xno"; then
+                VIK_CONFIG_DEFAULT_TILE_AGE=0;
+             elif test "x$withval" = "xyes"; then
+                AC_MSG_ERROR([Please, set a value for age of tiles])
+             else
+                VIK_CONFIG_DEFAULT_TILE_AGE=${withval}
+             fi],
+             [VIK_CONFIG_DEFAULT_TILE_AGE=30])
+AC_DEFINE_UNQUOTED(VIK_CONFIG_DEFAULT_TILE_AGE, ${VIK_CONFIG_DEFAULT_TILE_AGE},
+                   [Age of tiles before cheking it (in seconds)])
+
 dnl man pages processing
 DB2MAN_XSL=/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl
 AC_SUBST(DB2MAN_XSL)
@@ -320,6 +335,7 @@ echo "Geonames                         : $ac_cv_enable_geonames"
 echo "USGS 24k DEM                     : $ac_cv_enable_dem24k"
 echo "Realtime GPS Tracking            : $ac_cv_enable_realtimegpstracking"
 echo "Size of map cache (in memory)    : ${VIK_CONFIG_MAPCACHE_SIZE}"
+echo "Age of tiles (in seconds)        : ${VIK_CONFIG_DEFAULT_TILE_AGE}"
 echo "-------------------------------------------"
 echo ""
 echo "Configure finished, type 'make' to build."
index a53b0edd27ceaa110d875255bdc19dd06a844c84..95c4cb14acaf4cfbc4cadd03a7a537a091c732d9 100644 (file)
@@ -277,7 +277,7 @@ gboolean a_babel_convert_from_shellcommand ( VikTrwLayer *vt, const char *input_
 
 gboolean a_babel_convert_from_url ( VikTrwLayer *vt, const char *url, const char *input_type, BabelStatusFunc cb, gpointer user_data )
 {
-  static DownloadOptions options = {NULL, 0, a_check_kml_file};
+  static DownloadOptions options = { FALSE, NULL, 0, a_check_kml_file};
   gint fd_src;
   int fetch_ret;
   gboolean ret = FALSE;
index f230dca0927c1826656c920f1534a4c87255a62f..f4396d44a877ab0364dbbabeb77e83688b309608 100644 (file)
 
 #include <stdio.h>
 
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
@@ -117,7 +121,7 @@ void curl_download_init()
   curl_download_user_agent = g_strdup_printf ("%s/%s %s", PACKAGE, VERSION, curl_version());
 }
 
-int curl_download_uri ( const char *uri, FILE *f, DownloadOptions *options )
+int curl_download_uri ( const char *uri, FILE *f, DownloadOptions *options, time_t time_condition )
 {
   CURL *curl;
   CURLcode res = CURLE_FAILED_INIT;
@@ -126,43 +130,70 @@ int curl_download_uri ( const char *uri, FILE *f, DownloadOptions *options )
   g_debug("%s: uri=%s", __PRETTY_FUNCTION__, uri);
 
   curl = curl_easy_init ();
-  if ( curl )
-    {
-      if (vik_verbose)
-        curl_easy_setopt ( curl, CURLOPT_VERBOSE, 1 );
-      curl_easy_setopt ( curl, CURLOPT_URL, uri );
-      curl_easy_setopt ( curl, CURLOPT_WRITEDATA, f );
-      curl_easy_setopt ( curl, CURLOPT_WRITEFUNCTION, curl_write_func);
-      curl_easy_setopt ( curl, CURLOPT_NOPROGRESS, 0 );
-      curl_easy_setopt ( curl, CURLOPT_PROGRESSDATA, NULL );
-      curl_easy_setopt ( curl, CURLOPT_PROGRESSFUNCTION, curl_progress_func);
-      if (options != NULL) {
-        if(options->referer != NULL)
-          curl_easy_setopt ( curl, CURLOPT_REFERER, options->referer);
-        if(options->follow_location != 0) {
-          curl_easy_setopt ( curl, CURLOPT_FOLLOWLOCATION, 1);
-          curl_easy_setopt ( curl, CURLOPT_MAXREDIRS, options->follow_location);
-        }
-      }
-      curl_easy_setopt ( curl, CURLOPT_USERAGENT, curl_download_user_agent );
-      if ((cookie_file = get_cookie_file(FALSE)) != NULL)
-        curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_file);
-      res = curl_easy_perform ( curl );
-      curl_easy_cleanup ( curl );
+  if ( !curl ) {
+    return DOWNLOAD_ERROR;
+  }
+  if (vik_verbose)
+    curl_easy_setopt ( curl, CURLOPT_VERBOSE, 1 );
+  curl_easy_setopt ( curl, CURLOPT_URL, uri );
+  curl_easy_setopt ( curl, CURLOPT_WRITEDATA, f );
+  curl_easy_setopt ( curl, CURLOPT_WRITEFUNCTION, curl_write_func);
+  curl_easy_setopt ( curl, CURLOPT_NOPROGRESS, 0 );
+  curl_easy_setopt ( curl, CURLOPT_PROGRESSDATA, NULL );
+  curl_easy_setopt ( curl, CURLOPT_PROGRESSFUNCTION, curl_progress_func);
+  if (options != NULL) {
+    if(options->referer != NULL)
+      curl_easy_setopt ( curl, CURLOPT_REFERER, options->referer);
+    if(options->follow_location != 0) {
+      curl_easy_setopt ( curl, CURLOPT_FOLLOWLOCATION, 1);
+      curl_easy_setopt ( curl, CURLOPT_MAXREDIRS, options->follow_location);
+    }
+    if(options->check_file_server_time && time_condition != 0) {
+      /* if file exists, check against server if file is recent enough */
+      curl_easy_setopt ( curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
+      curl_easy_setopt ( curl, CURLOPT_TIMEVALUE, time_condition);
     }
-  return(res);
+  }
+  curl_easy_setopt ( curl, CURLOPT_USERAGENT, curl_download_user_agent );
+  if ((cookie_file = get_cookie_file(FALSE)) != NULL)
+    curl_easy_setopt(curl, CURLOPT_COOKIEFILE, cookie_file);
+  res = curl_easy_perform ( curl );
+  if (res == 0) {
+    glong response;
+    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+    if (response == 304) {         // 304 = Not Modified
+      res = DOWNLOAD_NO_NEWER_FILE;
+    } else if (response == 200 ||  // http: 200 = Ok
+               response == 226) {  // ftp:  226 = sucess
+      gdouble size;
+      /* verify if curl sends us any data - this is a workaround on using CURLOPT_TIMECONDITION 
+         when the server has a (incorrect) time earlier than the time on the file we already have */
+      curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &size);
+      if (size == 0)
+        res = DOWNLOAD_ERROR;
+      else
+        res = DOWNLOAD_NO_ERROR;
+    } else {
+      g_warning("%s: http response: %ld for uri %s (time_condition = %ld)\n", __FUNCTION__, response, uri, time_condition);
+      res = DOWNLOAD_ERROR;
+    }
+  } else {
+    res = DOWNLOAD_ERROR;
+  }
+  curl_easy_cleanup ( curl );
+  return res;
 }
 
-int curl_download_get_url ( const char *hostname, const char *uri, FILE *f, DownloadOptions *options, gboolean ftp )
+int curl_download_get_url ( const char *hostname, const char *uri, FILE *f, DownloadOptions *options, gboolean ftp, time_t time_condition )
 {
   int ret;
   gchar *full = NULL;
 
   /* Compose the full url */
   full = g_strdup_printf ( "%s://%s%s", (ftp?"ftp":"http"), hostname, uri );
-  ret = curl_download_uri ( full, f, options );
+  ret = curl_download_uri ( full, f, options, time_condition );
   g_free ( full );
   full = NULL;
 
-  return (ret ? -2 : 0);   /* -2 HTTP error */
+  return ret;
 }
index 0fc751842991b082be0763bf4be042637fa7541e..33b78ee06f3182f99180dacf282253376cb0b4d3 100644 (file)
@@ -27,7 +27,7 @@
 #include "download.h"
 
 void curl_download_init ();
-int curl_download_get_url ( const char *hostname, const char *uri, FILE *f, DownloadOptions *options, gboolean ftp );
-int curl_download_uri ( const char *uri, FILE *f, DownloadOptions *options );
+int curl_download_get_url ( const char *hostname, const char *uri, FILE *f, DownloadOptions *options, gboolean ftp, time_t time_condition );
+int curl_download_uri ( const char *uri, FILE *f, DownloadOptions *options, time_t time_condition );
 
 #endif
index 1f10ed124a06dddd0217f70abf21b6b59a55ecfd..1fabbf5e59a53f9db79a3ae0e7c9ac0c9f213923 100644 (file)
 
 #include <stdio.h>
 #include <ctype.h>
+#include <errno.h>
 #include <string.h>
+#include <sys/types.h>
+#include <utime.h>
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <glib/gi18n.h>
 
+
 #include "download.h"
 
 #include "curl_download.h"
@@ -89,41 +93,82 @@ gboolean a_check_kml_file(FILE* f)
   return check_file_first_line(f, kml_str);
 }
 
+static GList *file_list = NULL;
+static GMutex *file_list_mutex = NULL;
+
+void a_download_init (void)
+{
+       file_list_mutex = g_mutex_new();
+}
+
+static gboolean lock_file(const char *fn)
+{
+       gboolean locked = FALSE;
+       g_mutex_lock(file_list_mutex);
+       if (g_list_find(file_list, fn) == NULL)
+       {
+               // The filename is not yet locked
+               file_list = g_list_append(file_list, (gpointer)fn),
+               locked = TRUE;
+       }
+       g_mutex_unlock(file_list_mutex);
+       return locked;
+}
+
+static void unlock_file(const char *fn)
+{
+       g_mutex_lock(file_list_mutex);
+       file_list = g_list_remove(file_list, (gconstpointer)fn);
+       g_mutex_unlock(file_list_mutex);
+}
+
 static int download( const char *hostname, const char *uri, const char *fn, DownloadOptions *options, gboolean ftp)
 {
   FILE *f;
   int ret;
   gchar *tmpfilename;
   gboolean failure = FALSE;
+  time_t time_condition = 0;
 
   /* Check file */
   if ( g_file_test ( fn, G_FILE_TEST_EXISTS ) == TRUE )
   {
-    /* File exists: return */
-    return -3;
+    if (options != NULL && options->check_file_server_time) {
+      /* Get the modified time of this file */
+      struct stat buf;
+      g_stat ( fn, &buf );
+      time_condition = buf.st_mtime;
+      if ( (time(NULL) - time_condition) < options->check_file_server_time )
+                               /* File cache is too recent, so return */
+                               return -3;
+    } else {
+      /* Nothing to do as file already exists, so return */
+      return -3;
+    }
   } else {
     gchar *dir = g_path_get_dirname ( fn );
     g_mkdir_with_parents ( dir , 0777 );
     g_free ( dir );
-
-    /* create placeholder file */
-    if ( ! (f = g_fopen ( fn, "w+b" )) ) /* immediately open file so other threads won't -- prevents race condition */
-      return -4;
-    fclose ( f );
-    f = NULL;
   }
 
   tmpfilename = g_strdup_printf("%s.tmp", fn);
-  f = g_fopen ( tmpfilename, "w+b" );
+  if (!lock_file ( tmpfilename ) )
+  {
+    g_debug("%s: Couldn't take lock on temporary file \"%s\"\n", __FUNCTION__, tmpfilename);
+    g_free ( tmpfilename );
+    return -4;
+  }
+  f = g_fopen ( tmpfilename, "w+b" );  /* truncate file and open it */
   if ( ! f ) {
+    g_warning("Couldn't open temporary file \"%s\": %s", tmpfilename, g_strerror(errno));
     g_free ( tmpfilename );
-    g_remove ( fn ); /* couldn't create temporary. delete 0-byte file. */
     return -4;
   }
 
   /* Call the backend function */
-  ret = curl_download_get_url ( hostname, uri, f, options, ftp );
-  if (ret == -1 || ret == 1 || ret == -2) {
+  ret = curl_download_get_url ( hostname, uri, f, options, ftp, time_condition );
+
+  if (ret != DOWNLOAD_NO_ERROR && ret != DOWNLOAD_NO_NEWER_FILE) {
     g_debug("%s: download failed: curl_download_get_url=%d", __FUNCTION__, ret);
     failure = TRUE;
   }
@@ -136,19 +181,24 @@ static int download( const char *hostname, const char *uri, const char *fn, Down
   if (failure)
   {
     g_warning(_("Download error: %s"), fn);
-    fclose ( f );
-    f = NULL;
     g_remove ( tmpfilename );
+    unlock_file ( tmpfilename );
     g_free ( tmpfilename );
+    fclose ( f );
+    f = NULL;
     g_remove ( fn ); /* couldn't create temporary. delete 0-byte file. */
     return -1;
   }
 
+  if (ret == DOWNLOAD_NO_NEWER_FILE)
+    g_remove ( tmpfilename );
+  else
+    g_rename ( tmpfilename, fn ); /* move completely-downloaded file to permanent location */
+  unlock_file ( tmpfilename );
+  g_free ( tmpfilename );
   fclose ( f );
   f = NULL;
-  g_rename ( tmpfilename, fn ); /* move completely-downloaded file to permanent location */
-  g_free ( tmpfilename );
-  return ret;
+  return 0;
 }
 
 /* success = 0, -1 = couldn't connect, -2 HTTP error, -3 file exists, -4 couldn't write to file... */
index f4aa8df5e6d21cbcc3ae030017611f6c0adaca26..c2c20d2e2208f60300253e4e0fcc1ccb057be589 100644 (file)
@@ -31,6 +31,14 @@ gboolean a_check_html_file(FILE*);
 gboolean a_check_kml_file(FILE*);
 
 typedef struct {
+  /**
+   * Check if the server has a more recent file than the one we have before downloading it
+   * This uses http header If-Modified-Since
+   * Nevertheless, the current file cache must be older than the specified
+   * value.
+   */
+  time_t check_file_server_time;
+
   /**
    * The REFERER string to use.
    * Could be NULL.
@@ -47,10 +55,18 @@ typedef struct {
    * File content checker.
    */
   VikFileContentCheckerFunc check_file;
+
 } DownloadOptions;
 
+void a_download_init(void);
+
 /* TODO: convert to Glib */
 int a_http_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadOptions *opt );
 int a_ftp_download_get_url ( const char *hostname, const char *uri, const char *fn, DownloadOptions *opt );
 
+/* Error messages returned by download functions */
+enum { DOWNLOAD_NO_ERROR = 0,
+       DOWNLOAD_NO_NEWER_FILE,
+       DOWNLOAD_ERROR };
+
 #endif
index a55fde139742e161ac3b0c091d9f35efce6d603d..24e0b7bfd0d53a5a253315962d7aa40c1205d859 100644 (file)
@@ -44,10 +44,10 @@ static gboolean expedia_coord_to_mapcoord ( const VikCoord *src, gdouble xzoom,
 static void expedia_mapcoord_to_center_coord ( MapCoord *src, VikCoord *dest );
 static int expedia_download ( MapCoord *src, const gchar *dest_fn );
 
-static DownloadOptions expedia_options = { NULL, 2, a_check_map_file };
+static DownloadOptions expedia_options = { 0, NULL, 2, a_check_map_file };
 
 void expedia_init() {
-  VikMapsLayer_MapType map_type = { 5, 0, 0, VIK_VIEWPORT_DRAWMODE_EXPEDIA, expedia_coord_to_mapcoord, expedia_mapcoord_to_center_coord, expedia_download };
+  VikMapsLayer_MapType map_type = { 5, 0, 0, VIK_VIEWPORT_DRAWMODE_EXPEDIA, expedia_coord_to_mapcoord, expedia_mapcoord_to_center_coord, expedia_download, &expedia_options };
   maps_layer_register_type(_("Expedia Street Maps"), 5, &map_type);
 }
 
index 4da17e45d785cecd41814891d295945537953bd8..fcf0cabae5903a927d0838cedddefee17843975b 100644 (file)
@@ -398,7 +398,7 @@ gchar *download_url(gchar *uri)
   tmp_file = fdopen(tmp_fd, "r+");
 
   // TODO: curl may not be available
-  if (curl_download_uri(uri, tmp_file, NULL)) {  // error
+  if (curl_download_uri(uri, tmp_file, NULL, 0)) {  // error
     fclose(tmp_file);
     tmp_file = NULL;
     g_remove(tmpname);
index f9cb614c12de0ebd92fe881ac5f7b08764cf4af9..bf98f64ab3cc445d0bd29764914f219cce3de5e7 100644 (file)
@@ -41,7 +41,7 @@
 #define GOOGLE_GOTO_PATTERN_2 ",lng:"
 #define GOOGLE_GOTO_NOT_FOUND "not understand the location"
 
-static DownloadOptions googlesearch_options = { "http://maps.google.com/", 0, a_check_map_file };
+static DownloadOptions googlesearch_options = { 0, "http://maps.google.com/", 0, a_check_map_file };
 
 static void google_goto_tool_class_init ( GoogleGotoToolClass *klass );
 static void google_goto_tool_init ( GoogleGotoTool *vwd );
index 81cd6ea3e8d423890d3d29e646c5090a341648fd..5bbd022736ee2021dbe49892cbc13113c5cb9774 100644 (file)
@@ -165,6 +165,7 @@ int main( int argc, char *argv[] )
   if (!vik_debug)
     g_log_set_handler (NULL, G_LOG_LEVEL_DEBUG, mute_log, NULL);
 
+  a_download_init();
   curl_download_init();
 
   a_preferences_init ();
index 50bc7bcd667107a13de1cbe68ae5ef563b6d1ee5..e00dd41ff3aa7141fc8352de8b90a24f98f9504a 100644 (file)
--- a/src/osm.c
+++ b/src/osm.c
 
 /* initialisation */
 void osm_init () {
-  VikMapSource *osmarender_type = VIK_MAP_SOURCE(vik_slippy_map_source_new_with_id(12, "OpenStreetMap (Osmarender)", "tah.openstreetmap.org", "/Tiles/tile/%d/%d/%d.png"));
-  VikMapSource *mapnik_type = VIK_MAP_SOURCE(vik_slippy_map_source_new_with_id( 13, "OpenStreetMap (Mapnik)", "tile.openstreetmap.org", "/%d/%d/%d.png"));
-  VikMapSource *maplint_type = VIK_MAP_SOURCE(vik_slippy_map_source_new_with_id( 14, "OpenStreetMap (Maplint)", "tah.openstreetmap.org", "/Tiles/maplint.php/%d/%d/%d.png"));
-  VikMapSource *cycle_type = VIK_MAP_SOURCE(vik_slippy_map_source_new_with_id( 17, "OpenStreetMap (Cycle)", "thunderflames.org/tiles/cycle/", "%d/%d/%d.png" ));
+  VikMapSource *osmarender_type = 
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
+                                "id", 12,
+                                "label", "OpenStreetMap (Osmarender)",
+                                "hostname", "tah.openstreetmap.org",
+                                "url", "/Tiles/tile/%d/%d/%d.png",
+                                "check-file-server-time", VIK_CONFIG_DEFAULT_TILE_AGE,
+                                NULL));
+  VikMapSource *mapnik_type =
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
+                                "id", 13,
+                                "label", "OpenStreetMap (Mapnik)",
+                                "hostname", "tile.openstreetmap.org",
+                                "url", "/%d/%d/%d.png",
+                                "check-file-server-time", VIK_CONFIG_DEFAULT_TILE_AGE,
+                                NULL));
+  VikMapSource *maplint_type =
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
+                                "id", 14,
+                                "label", "OpenStreetMap (Maplint)",
+                                "hostname", "tah.openstreetmap.org",
+                                "url", "/Tiles/maplint.php/%d/%d/%d.png",
+                                "check-file-server-time", VIK_CONFIG_DEFAULT_TILE_AGE,
+                                NULL));
+  VikMapSource *cycle_type =
+    VIK_MAP_SOURCE(g_object_new(VIK_TYPE_SLIPPY_MAP_SOURCE,
+                                "id", 17,
+                                "label", "OpenStreetMap (Cycle)",
+                                "hostname", "thunderflames.org/tiles/cycle/",
+                                "url", "%d/%d/%d.png",
+                                "check-file-server-time", VIK_CONFIG_DEFAULT_TILE_AGE,
+                                NULL));
 
   maps_layer_register_map_source (osmarender_type);
   maps_layer_register_map_source (mapnik_type);
index 63ecec9d529e58ba9d8dd021eb06c88f9c5c0bdf..53d97a054be89b9434740b657de14e05d1769b50 100644 (file)
@@ -782,7 +782,7 @@ static void srtm_dem_download_thread ( DEMDownloadParams *p, gpointer threaddata
                (intlon >= 0) ? 'E' : 'W',
                ABS(intlon) );
 
-  static DownloadOptions options = { NULL, 0, a_check_map_file };
+  static DownloadOptions options = { 0, NULL, 0, a_check_map_file };
   a_http_download_get_url ( SRTM_HTTP_SITE, src_fn, p->dest, &options );
   g_free ( src_fn );
 }
index 4ed2dfeed227916ba2124ed788a18af6ed378b20..81f18b4291854598ca79332db245d77afbff2886 100644 (file)
@@ -255,7 +255,7 @@ int vik_goto_tool_get_coord ( VikGotoTool *self, VikWindow *vw, VikViewport *vvp
   uri = g_strdup_printf(vik_goto_tool_get_url_format(self), escaped_srch_str);
 
   /* TODO: curl may not be available */
-  if (curl_download_uri(uri, tmp_file, vik_goto_tool_get_download_options(self))) {  /* error */
+  if (curl_download_uri(uri, tmp_file, vik_goto_tool_get_download_options(self), 0)) {  /* error */
     fclose(tmp_file);
     tmp_file = NULL;
     ret = -1;
index f2453be53ecaf1a49f8e2b548bb861f028360393..04a6fd9615085bb32ba987d9161738577025848e 100644 (file)
@@ -199,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 */
 
 
 /****************************************/
@@ -636,7 +640,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 ( vik_map_source_supports_if_modified_since (map) )
+        // 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 ( vik_map_source_get_tilesize_x(map) == 0 && !existence_only ) {
@@ -837,6 +846,9 @@ static int 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;
 
@@ -1045,11 +1057,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)
@@ -1082,6 +1100,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 );
@@ -1171,11 +1193,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);
@@ -1192,11 +1219,18 @@ 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 ( vik_map_source_supports_if_modified_since (MAPS_LAYER_NTH_TYPE(vml->maptype)) ) {
+    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 );
index 48a679f08d555101f21339e0b1913ce5fb727052..de756992f5d122124a3e14876c0c71d14e23d98c 100644 (file)
@@ -30,6 +30,8 @@ static void vik_map_source_init (VikMapSource *object);
 static void vik_map_source_finalize (GObject *object);
 static void vik_map_source_class_init (VikMapSourceClass *klass);
 
+static void _supports_if_modified_since (VikMapSource *object);
+
 G_DEFINE_TYPE_EXTENDED (VikMapSource, vik_map_source, G_TYPE_OBJECT, (GTypeFlags)G_TYPE_FLAG_ABSTRACT,);
 
 static void
@@ -56,6 +58,7 @@ vik_map_source_class_init (VikMapSourceClass *klass)
        klass->get_tilesize_x = NULL;
        klass->get_tilesize_y = NULL;
        klass->get_drawmode = NULL;
+       klass->supports_if_modified_since = _supports_if_modified_since;
        klass->coord_to_mapcoord = NULL;
        klass->mapcoord_to_center_coord = NULL;
        klass->download = NULL;
@@ -63,6 +66,12 @@ vik_map_source_class_init (VikMapSourceClass *klass)
        object_class->finalize = vik_map_source_finalize;
 }
 
+void
+_supports_if_modified_since (VikMapSource *self)
+{
+       // Default feature: does not support
+       return FALSE;
+}
 
 guint8
 vik_map_source_get_uniq_id (VikMapSource *self)
@@ -129,6 +138,19 @@ vik_map_source_get_drawmode (VikMapSource *self)
        return (*klass->get_drawmode)(self);
 }
 
+gboolean
+vik_map_source_supports_if_modified_since (VikMapSource * self)
+{
+       VikMapSourceClass *klass;
+       g_return_val_if_fail (self != NULL, 0);
+       g_return_val_if_fail (VIK_IS_MAP_SOURCE (self), 0);
+       klass = VIK_MAP_SOURCE_GET_CLASS(self);
+
+       g_return_val_if_fail (klass->supports_if_modified_since != NULL, 0);
+
+       return (*klass->supports_if_modified_since)(self);
+}
+
 gboolean
 vik_map_source_coord_to_mapcoord (VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
 {
index 29080ffd61f2897fca6059e0bfc12dfe33ed0d10..c02fc5c152facf8903df7e4b40516f851f02f593 100644 (file)
@@ -47,6 +47,7 @@ struct _VikMapSourceClass
        guint16 (* get_tilesize_x) (VikMapSource * self);
        guint16 (* get_tilesize_y) (VikMapSource * self);
        VikViewportDrawMode (* get_drawmode) (VikMapSource * self);
+       gboolean (* supports_if_modified_since) (VikMapSource * self);
        gboolean (* coord_to_mapcoord) (VikMapSource * self, const VikCoord * src, gdouble xzoom, gdouble yzoom, MapCoord * dest);
        void (* mapcoord_to_center_coord) (VikMapSource * self, MapCoord * src, VikCoord * dest);
        int (* download) (VikMapSource * self, MapCoord * src, const gchar * dest_fn);
@@ -64,6 +65,7 @@ const gchar *vik_map_source_get_label (VikMapSource * self);
 guint16 vik_map_source_get_tilesize_x (VikMapSource * self);
 guint16 vik_map_source_get_tilesize_y (VikMapSource * self);
 VikViewportDrawMode vik_map_source_get_drawmode (VikMapSource * self);
+gboolean vik_map_source_supports_if_modified_since (VikMapSource * self);
 gboolean vik_map_source_coord_to_mapcoord (VikMapSource * self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
 void vik_map_source_mapcoord_to_center_coord (VikMapSource * self, MapCoord *src, VikCoord *dest);
 int vik_map_source_download (VikMapSource * self, MapCoord * src, const gchar * dest_fn);
index 99ef39ec2cdaac4cc21ebfb71adedc52669dfa55..44bf8b3174c8e50997f399d42917174ae7a02dc9 100644 (file)
@@ -30,6 +30,7 @@
 static gboolean _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest );
 static void _mapcoord_to_center_coord ( VikMapSource *self, MapCoord *src, VikCoord *dest );
 static int _download ( VikMapSource *self, MapCoord *src, const gchar *dest_fn );
+static gboolean _supports_if_modified_since (VikMapSource *self );
 
 static gchar *_get_uri( VikSlippyMapSource *self, MapCoord *src );
 static gchar *_get_hostname( VikSlippyMapSource *self );
@@ -54,6 +55,7 @@ enum
   PROP_URL,
   PROP_REFERER,
   PROP_FOLLOW_LOCATION,
+  PROP_CHECK_FILE_SERVER_TIME,
 };
 
 G_DEFINE_TYPE_EXTENDED (VikSlippyMapSource, vik_slippy_map_source, VIK_TYPE_MAP_SOURCE_DEFAULT, (GTypeFlags)0,);
@@ -69,6 +71,7 @@ vik_slippy_map_source_init (VikSlippyMapSource *self)
   priv->options.referer = NULL;
   priv->options.follow_location = 0;
   priv->options.check_file = a_check_map_file;
+  priv->options.check_file_server_time = 0;
 
   g_object_set (G_OBJECT (self),
                 "tilesize-x", 256,
@@ -123,6 +126,10 @@ vik_slippy_map_source_set_property (GObject      *object,
       priv->options.follow_location = g_value_get_long (value);
       break;
 
+    case PROP_CHECK_FILE_SERVER_TIME:
+      priv->options.check_file_server_time = g_value_get_uint (value);
+      break;
+
     default:
       /* We don't have any other property... */
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -157,6 +164,10 @@ vik_slippy_map_source_get_property (GObject    *object,
       g_value_set_long (value, priv->options.follow_location);
       break;
 
+    case PROP_CHECK_FILE_SERVER_TIME:
+      g_value_set_uint (value, priv->options.check_file_server_time);
+      break;
+         
     default:
       /* We don't have any other property... */
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -178,6 +189,7 @@ vik_slippy_map_source_class_init (VikSlippyMapSourceClass *klass)
        parent_class->coord_to_mapcoord =        _coord_to_mapcoord;
        parent_class->mapcoord_to_center_coord = _mapcoord_to_center_coord;
        parent_class->download =                 _download;
+       parent_class->supports_if_modified_since = _supports_if_modified_since;
        
        /* Default implementation of methods */
        klass->get_uri = _get_uri;
@@ -213,6 +225,15 @@ vik_slippy_map_source_class_init (VikSlippyMapSourceClass *klass)
                                0  /* default value */,
                                G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
        g_object_class_install_property (object_class, PROP_FOLLOW_LOCATION, pspec);
+       
+       pspec = g_param_spec_uint ("check-file-server-time",
+                                  "Check file server time",
+                               "Age of current cache before redownloading tile",
+                               0  /* minimum value */,
+                               G_MAXUINT16 /* maximum value */,
+                               0  /* default value */,
+                               G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
+       g_object_class_install_property (object_class, PROP_CHECK_FILE_SERVER_TIME, pspec);
 
        g_type_class_add_private (klass, sizeof (VikSlippyMapSourcePrivate));
        
@@ -276,6 +297,17 @@ vik_slippy_map_source_get_download_options( VikSlippyMapSource *self )
        return (*klass->get_download_options)(self);
 }
 
+gboolean
+_supports_if_modified_since (VikMapSource *self)
+{
+       g_return_val_if_fail (VIK_IS_SLIPPY_MAP_SOURCE(self), FALSE);
+       
+    VikSlippyMapSourcePrivate *priv = VIK_SLIPPY_MAP_SOURCE_PRIVATE(self);
+       
+       g_debug ("%s: priv->options.check_file_server_time = %d", __FUNCTION__, priv->options.check_file_server_time);
+       
+       return priv->options.check_file_server_time != 0;
+}
 static gboolean
 _coord_to_mapcoord ( VikMapSource *self, const VikCoord *src, gdouble xzoom, gdouble yzoom, MapCoord *dest )
 {