PROP_CACHE_DIR,
};
+typedef struct _ProgressUpdateInfo ProgressUpdateInfo;
+struct _ProgressUpdateInfo {
+ gchar *src_str;
+ gchar *dest_str;
+ TileRepo *repo;
+ guint tilex, tiley, zoom; /* for refresh. */
+ gint retries; /* if equal to zero, it means we're DELETING maps. */
+ guint priority;
+ FILE *file;
+};
+
#if 0
#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TILE_REPO_TYPE, TileRepoPrivate))
#endif
switch (prop_id) {
case PROP_NAME:
+ if (tr->name)
+ g_free(tr->name);
+ tr->name=g_value_dup_string(value);
+ break;
case PROP_URL:
+ if (tr->url)
+ g_free(tr->url);
+ tr->url=g_value_dup_string(value);
+ tile_repo_set_type(tr);
+ break;
case PROP_CACHE_DIR:
+ if (tr->cache_dir)
+ g_free(tr->cache_dir);
+ tr->cache_dir=g_value_dup_string(value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
switch (prop_id) {
case PROP_NAME:
+ g_value_set_string(value, tr->name);
+ break;
case PROP_URL:
+ g_value_set_string(value, tr->url);
+ break;
case PROP_CACHE_DIR:
+ g_value_set_string(value, tr->cache_dir);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
object_class->get_property=tile_repo_get_property;
}
+static gboolean
+get_next_pui(gpointer key, gpointer value, ProgressUpdateInfo **data)
+{
+*data = key;
+return TRUE;
+}
+
+static gint
+download_comparefunc(const ProgressUpdateInfo *a, const ProgressUpdateInfo *b, gpointer user_data)
+{
+gint diff = (a->priority - b->priority);
+if (diff)
+ return diff;
+diff = (a->tilex - b->tilex);
+if (diff)
+ return diff;
+diff = (a->tiley - b->tiley);
+if (diff)
+ return diff;
+diff = (a->zoom - b->zoom);
+if (diff)
+ return diff;
+diff = (a->repo - b->repo);
+if (diff)
+ return diff;
+/* Otherwise, deletes are "greatest" (least priority). */
+if (!a->retries)
+ return (b->retries ? -1 : 0);
+else if (!b->retries)
+ return (a->retries ? 1 : 0);
+/* Do updates after non-updates (because they'll both be done anyway). */
+return (a->retries - b->retries);
+}
+
+static void
+progress_update_info_free(ProgressUpdateInfo *pui)
+{
+g_free(pui->src_str);
+g_free(pui->dest_str);
+g_slice_free(ProgressUpdateInfo, pui);
+}
+
/**
* tile_repo_new:
*
tr->dl_zoom_steps=1;
tr->double_size=0;
tr->nextable=FALSE;
+
+tr->download.cond=g_cond_new();
+tr->download.mutex=g_mutex_new();
+tr->download.curl_easy_queue=g_queue_new();
+tr->download.pui_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+tr->download.downloading_tree=g_tree_new_full((GCompareDataFunc)download_comparefunc, NULL, (GDestroyNotify) progress_update_info_free, NULL);
+tr->download.pui_by_easy=g_hash_table_new(g_direct_hash, g_direct_equal);
+tr->download.curl_multi=curl_multi_init();
+#ifdef CURL_PIPELINE
+curl_multi_setopt(tr->download.curl_multi, CURLMOPT_PIPELINING, 1);
+#endif
}
/**
tr=tile_repo_new();
g_return_val_if_fail(tr, NULL);
-g_debug("REPOSTR: %s", str);
-
/* Parse name. */
token=strsep(&str, "\n\t");
if (token)
tr->double_size, tr->nextable);
}
+static void
+download_stop(TileRepo *tr)
+{
+}
+
/**
* tile_repo_free:
* @tr
if (tr->icache)
image_cache_free(tr->icache);
+if (tr->download.curl_multi) {
+ gint num_transfers;
+
+ /* Finish up all downloads. */
+ while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(tr->download.curl_multi, &num_transfers) || num_transfers)
+ g_debug("NT: %d", num_transfers);
+
+ /* Stop all transfers and cleanup */
+ download_stop(tr);
+
+ curl_multi_cleanup(tr->download.curl_multi);
+}
+
+if (tr->download.curl_sid)
+ g_source_remove(tr->download.curl_sid);
+if (tr->download.pui_tree)
+ g_tree_destroy(tr->download.pui_tree);
+if (tr->download.downloading_tree)
+ g_tree_destroy(tr->download.downloading_tree);
+if (tr->download.pui_by_easy)
+ g_hash_table_destroy(tr->download.pui_by_easy);
+if (tr->download.curl_easy_queue)
+ g_queue_free(tr->download.curl_easy_queue);
+
g_object_unref(tr);
}
return g_file_test(tr->cache_dir, G_FILE_TEST_EXISTS);
}
+static void
+convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel, gchar *buffer, const gchar initial, const gchar * const quadrant)
+{
+gchar *ptr = buffer;
+gint n;
+
+if (initial)
+ *ptr++ = initial;
+
+for (n = 16 - zoomlevel; n >= 0; n--) {
+ gint xbit = (x >> n) & 1;
+ gint ybit = (y >> n) & 1;
+ *ptr++ = quadrant[xbit + 2 * ybit];
+}
+*ptr++ = '\0';
+}
+
+
+/**
+ * til
+ * Construct the URL that we should fetch, based on the current URI format.
+ * This method works differently depending on if a "%s" string is present in
+ * the URI format, since that would indicate a quadtree-based map coordinate
+ * system.
+ */
+static gchar *
+tile_repo_construct_url(TileRepo *tr, guint tilex, guint tiley, guint zoom)
+{
+switch (tr->type) {
+case REPOTYPE_XYZ:
+ return g_strdup_printf(tr->url, tilex, tiley, zoom);
+case REPOTYPE_XYZ_INV:
+ return g_strdup_printf(tr->url, 17 - zoom, tilex, tiley);
+case REPOTYPE_QUAD_QRST: {
+ gchar location[32];
+ convert_coords_to_quadtree_string(tilex, tiley, zoom, location, 't', "qrts");
+ return g_strdup_printf(tr->url, location);
+ }
+case REPOTYPE_QUAD_ZERO: {
+ /* This is a zero-based quadtree URI. */
+ gchar location[32];
+ convert_coords_to_quadtree_string(tilex, tiley, zoom, location, '\0', "0123");
+ return g_strdup_printf(tr->url, location);
+ }
+#ifdef MAP_DOWNLOAD_WMD
+case REPOTYPE_WMS:
+ return map_convert_wms_to_wms(tilex, tiley, zoom, tr->url);
+#endif
+default:
+ return NULL;
+}
+return "";
+}
+
GdkPixbuf *
tile_repo_load(TileRepo *tr, guint tilex, guint tiley, gint zoom, gint zoff, gboolean fast_fail)
{