2 * Copyright (C) 2006, 2007 John Costigan.
4 * POI and GPS-Info code originally written by Cezary Jackiewicz.
6 * Default map data provided by http://www.openstreetmap.org/
8 * This file is part of Maemo Mapper.
10 * Maemo Mapper is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * Maemo Mapper is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Maemo Mapper. If not, see <http://www.gnu.org/licenses/>.
33 #include <glib/gstdio.h>
39 # include <hildon/hildon-help.h>
40 # include <hildon/hildon-note.h>
41 # include <hildon/hildon-file-chooser-dialog.h>
42 # include <hildon/hildon-number-editor.h>
43 # include <hildon/hildon-banner.h>
45 # include <osso-helplib.h>
46 # include <hildon-widgets/hildon-note.h>
47 # include <hildon-widgets/hildon-file-chooser-dialog.h>
48 # include <hildon-widgets/hildon-number-editor.h>
49 # include <hildon-widgets/hildon-banner.h>
50 # include <hildon-widgets/hildon-input-mode-hint.h>
66 typedef struct _RepoManInfo RepoManInfo;
74 typedef struct _RepoEditInfo RepoEditInfo;
75 struct _RepoEditInfo {
78 GtkWidget *txt_db_filename;
79 GtkWidget *num_dl_zoom_steps;
80 GtkWidget *num_view_zoom_steps;
81 GtkWidget *chk_double_size;
82 GtkWidget *chk_nextable;
83 GtkWidget *btn_browse;
84 GtkWidget *btn_compact;
85 GtkWidget *num_min_zoom;
86 GtkWidget *num_max_zoom;
87 BrowseInfo browse_info;
92 typedef struct _RepoLayersInfo RepoLayersInfo;
93 struct _RepoLayersInfo {
96 GtkListStore *layers_store;
97 GtkWidget *layers_list;
102 typedef struct _LayerEditInfo LayerEditInfo;
103 struct _LayerEditInfo {
109 GtkWidget *num_autofetch;
110 GtkWidget *chk_visible;
116 typedef struct _MapmanInfo MapmanInfo;
122 /* The "Setup" tab. */
123 GtkWidget *rad_download;
124 GtkWidget *rad_delete;
125 GtkWidget *chk_overwrite;
126 GtkWidget *rad_by_area;
127 GtkWidget *rad_by_route;
128 GtkWidget *num_route_radius;
130 /* The "Area" tab. */
131 GtkWidget *txt_topleft_lat;
132 GtkWidget *txt_topleft_lon;
133 GtkWidget *txt_botright_lat;
134 GtkWidget *txt_botright_lon;
136 /* The "Zoom" tab. */
137 GtkWidget *chk_zoom_levels[MAX_ZOOM + 1];
141 typedef struct _CompactInfo CompactInfo;
142 struct _CompactInfo {
146 const gchar *db_filename;
150 typedef struct _MapCacheKey MapCacheKey;
151 struct _MapCacheKey {
158 typedef struct _MapCacheEntry MapCacheEntry;
159 struct _MapCacheEntry {
170 typedef struct _MapCacheList MapCacheList;
171 struct _MapCacheList {
178 typedef struct _MapCache MapCache;
180 MapCacheList lists[4];
189 static MapCache _map_cache;
191 const gchar* layer_timestamp_key = "tEXt::mm_ts";
195 mapdb_get_data(RepoData *repo, gint zoom, gint tilex, gint tiley, gchar **data)
198 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
199 repo->name, zoom, tilex, tiley);
205 /* There is no cache. Return NULL. */
206 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__,size);
211 /* Attempt to retrieve map from database. */
212 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
213 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
214 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
215 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select))
217 const gchar *bytes = NULL;
218 size = sqlite3_column_bytes(repo->stmt_map_select, 0);
220 /* "Pixbufs" of size less than or equal to MAX_PIXBUF_DUP_SIZE are
221 * actually keys into the dups table. */
222 if(size <= MAX_PIXBUF_DUP_SIZE)
224 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
225 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_select, 1, hash)
226 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_select))
228 bytes = sqlite3_column_blob(repo->stmt_dup_select, 0);
229 size = sqlite3_column_bytes(repo->stmt_dup_select, 0);
233 /* Not there? Delete the entry, then. */
234 if(SQLITE_OK != sqlite3_bind_int(
235 repo->stmt_map_delete, 1, zoom)
236 || SQLITE_OK != sqlite3_bind_int(
237 repo->stmt_map_delete, 2, tilex)
238 || SQLITE_OK != sqlite3_bind_int(
239 repo->stmt_map_delete, 3, tiley)
240 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
242 printf("Error in stmt_map_delete: %s\n",
243 sqlite3_errmsg(repo->db));
245 sqlite3_reset(repo->stmt_map_delete);
247 /* We have no bytes to return to the caller. */
251 /* Don't reset the statement yet - we need the blob. */
255 bytes = sqlite3_column_blob(repo->stmt_map_select, 0);
259 *data = g_slice_alloc(size);
260 memcpy(*data, bytes, size);
262 if(size <= MAX_PIXBUF_DUP_SIZE)
263 sqlite3_reset(repo->stmt_dup_select);
265 sqlite3_reset(repo->stmt_map_select);
274 d.dptr = (gchar*)&key;
275 d.dsize = sizeof(key);
276 d = gdbm_fetch(repo->db, d);
280 *data = g_slice_alloc(size);
281 memcpy(*data, d.dptr, size);
287 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__, size);
291 static void map_cache_list_remove(MapCacheList *_list, MapCacheEntry *_entry)
293 _list->size -= _entry->size;
294 _list->data_sz -= _entry->data_sz;
295 *(_entry->prev != NULL?&_entry->prev->next:&_list->head) = _entry->next;
296 *(_entry->next != NULL?&_entry->next->prev:&_list->tail) = _entry->prev;
299 static void map_cache_list_prepend(MapCacheList *_list, int _li,
300 MapCacheEntry *_entry)
303 _entry->next = _list[_li].head;
304 *(_list[_li].head != NULL?&_list[_li].head->prev:&_list[_li].tail) = _entry;
305 _list[_li].head = _entry;
306 _list[_li].size += _entry->size;
307 _list[_li].data_sz += _entry->data_sz;
311 static guint map_cache_key_hash(gconstpointer _key){
312 const MapCacheKey *key;
313 key = (const MapCacheKey *)_key;
314 return g_direct_hash(key->repo)+g_int_hash(&key->zoom)+
315 g_int_hash(&key->tilex)+g_int_hash(&key->tiley);
318 static gboolean map_cache_key_equal(gconstpointer _v1, gconstpointer _v2){
319 const MapCacheKey *key1;
320 const MapCacheKey *key2;
321 key1 = (const MapCacheKey *)_v1;
322 key2 = (const MapCacheKey *)_v2;
323 return key1->tilex == key2->tilex && key1->tiley == key2->tiley &&
324 key1->zoom == key2->zoom && key1->repo == key2->repo;
327 static void map_cache_entry_make_pixbuf(MapCacheEntry *_entry){
328 if (_entry->data != NULL)
331 GdkPixbufLoader *loader;
333 loader = gdk_pixbuf_loader_new();
334 gdk_pixbuf_loader_write(loader, _entry->data, _entry->data_sz, NULL);
335 gdk_pixbuf_loader_close(loader, &error);
338 _entry->pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
339 _entry->size = _entry->data_sz+
340 gdk_pixbuf_get_rowstride(_entry->pixbuf)*
341 gdk_pixbuf_get_height(_entry->pixbuf);
342 g_object_unref(loader);
345 g_object_unref(loader);
346 g_slice_free1(_entry->data_sz, _entry->data);
350 _entry->pixbuf = NULL;
351 _entry->size = _entry->data_sz;
354 static void map_cache_entry_free_pixbuf(MapCacheEntry *_entry){
355 if(_entry->pixbuf!=NULL)
357 g_object_unref(_entry->pixbuf);
358 _entry->pixbuf = NULL;
362 static void map_cache_entry_free(MapCacheEntry *_entry){
363 if(_entry->list >= 0)
364 map_cache_list_remove(_map_cache.lists+_entry->list, _entry);
365 map_cache_entry_free_pixbuf(_entry);
366 g_slice_free1(_entry->data_sz, _entry->data);
367 g_slice_free(MapCacheEntry, _entry);
371 map_cache_replace(size_t _size, gboolean _b2)
375 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
376 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
378 while(total_size+_size > _map_cache.cache_size)
380 MapCacheEntry *entry;
382 if(_map_cache.lists[0].tail != NULL &&
383 (_map_cache.lists[0].size > _map_cache.p ||
384 (_b2 && _map_cache.lists[0].size == _map_cache.p)))
388 entry = _map_cache.lists[list].tail;
391 map_cache_list_remove(_map_cache.lists+list, entry);
392 map_cache_list_prepend(_map_cache.lists, list+1, entry);
393 total_size -= entry->size - entry->data_sz;
401 map_cache_evict(size_t _size)
405 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
406 +_map_cache.lists[2].size+_map_cache.lists[3].size;
407 max_size = _map_cache.cache_size<<1;
410 if(_map_cache.lists[0].size+_map_cache.lists[1].size+_size >
411 _map_cache.cache_size)
413 if(_map_cache.lists[1].tail != NULL)
415 g_hash_table_remove(_map_cache.entries,
416 &_map_cache.lists[1].tail->key);
417 map_cache_replace(_size, FALSE);
419 else if(_map_cache.lists[0].tail != NULL)
421 g_hash_table_remove(_map_cache.entries,
422 &_map_cache.lists[0].tail->key);
426 else if(total_size+_size > _map_cache.cache_size)
428 if(total_size+_size > max_size &&
429 _map_cache.lists[3].tail != NULL)
431 g_hash_table_remove(_map_cache.entries,
432 &_map_cache.lists[3].tail->key);
433 map_cache_replace(_size, FALSE);
435 else if(!map_cache_replace(_size, FALSE))
439 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
440 +_map_cache.lists[2].size+_map_cache.lists[3].size;
445 map_cache_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
448 MapCacheEntry *entry;
453 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
456 map_cache_list_remove(_map_cache.lists+entry->list, entry);
457 if(entry->pixbuf == NULL)
461 map_cache_entry_make_pixbuf(entry);
462 bsize = _map_cache.lists[entry->list].size+entry->size;
465 dp = _map_cache.lists[entry->list^2].size/bsize;
471 if(_map_cache.p > _map_cache.cache_size)
472 _map_cache.p = _map_cache.cache_size;
473 map_cache_replace(entry->size, FALSE);
477 if(dp > _map_cache.p)
481 map_cache_replace(entry->size, TRUE);
487 map_cache_list_prepend(_map_cache.lists, 2, entry);
493 data_sz = mapdb_get_data(repo, zoom, tilex, tiley, &data);
494 entry = g_slice_new(MapCacheEntry);
495 *&entry->key = *&key;
497 entry->data_sz = data_sz;
498 map_cache_entry_make_pixbuf(entry);
499 map_cache_evict(entry->size);
500 map_cache_list_prepend(_map_cache.lists, 0, entry);
501 g_hash_table_insert(_map_cache.entries, &entry->key, entry);
504 if(entry->pixbuf != NULL)
505 g_object_ref(entry->pixbuf);
506 return entry->pixbuf;
510 map_cache_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
511 gchar *data,guint size)
514 MapCacheEntry *entry;
519 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
522 g_slice_free1(entry->data_sz, entry->data);
523 entry->data = g_slice_alloc(size);
524 memcpy(entry->data, data, size);
525 entry->data_sz = size;
526 if(entry->pixbuf != NULL)
528 map_cache_entry_free_pixbuf(entry);
529 map_cache_list_remove(_map_cache.lists+entry->list, entry);
530 map_cache_list_prepend(_map_cache.lists, entry->list+1, entry);
536 map_cache_remove(RepoData *repo, gint zoom, gint tilex, gint tiley)
543 g_hash_table_remove(_map_cache.entries, &key);
547 map_cache_init_unlocked(size_t cache_size)
549 if(_map_cache.entries == NULL)
550 _map_cache.entries = g_hash_table_new_full(map_cache_key_hash,
551 map_cache_key_equal, NULL, (GDestroyNotify)map_cache_entry_free);
552 _map_cache.cache_size = cache_size;
553 if(_map_cache.p > cache_size)
554 _map_cache.p = cache_size;
559 map_cache_init(size_t cache_size)
561 g_mutex_lock(_mapdb_mutex);
562 map_cache_init_unlocked(cache_size);
563 g_mutex_unlock(_mapdb_mutex);
567 map_cache_resize(size_t cache_size)
570 g_mutex_lock(_mapdb_mutex);
571 _map_cache.cache_size = cache_size;
572 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
573 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
574 g_mutex_unlock(_mapdb_mutex);
579 map_cache_destroy_unlocked(void)
581 if(_map_cache.entries != NULL)
583 g_hash_table_destroy(_map_cache.entries);
584 _map_cache.entries = NULL;
585 printf("thits: %u (%0.2f%%) bhits: %u (%0.2f%%) "
586 "misses: %u (%0.2f%%)\n",
587 _map_cache.thits, 100*_map_cache.thits/(double)(
588 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
589 _map_cache.bhits, 100*_map_cache.bhits/(double)(
590 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
591 _map_cache.misses, 100*_map_cache.misses/(double)(
592 _map_cache.thits+_map_cache.bhits+_map_cache.misses));
596 map_cache_destroy(void)
598 g_mutex_lock(_mapdb_mutex);
599 map_cache_destroy_unlocked();
600 g_mutex_unlock(_mapdb_mutex);
605 map_cache_clean (void)
607 g_mutex_lock(_mapdb_mutex);
608 gint old_size = _map_cache.cache_size;
609 map_cache_destroy_unlocked();
610 map_cache_init_unlocked(old_size);
611 g_mutex_unlock(_mapdb_mutex);
616 mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley)
619 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
620 repo->name, zoom, tilex, tiley);
622 g_mutex_lock(_mapdb_mutex);
626 /* There is no cache. Return FALSE. */
627 g_mutex_unlock(_mapdb_mutex);
628 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
632 /* Search the cache first. */
635 MapCacheEntry *entry;
640 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
644 ret = entry->data != NULL;
645 g_mutex_unlock(_mapdb_mutex);
651 /* Attempt to retrieve map from database. */
652 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom)
653 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex)
654 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley)
655 && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists)
656 && sqlite3_column_int(repo->stmt_map_exists, 0) > 0)
664 sqlite3_reset(repo->stmt_map_exists);
673 d.dptr = (gchar*)&key;
674 d.dsize = sizeof(key);
675 exists = gdbm_exists(repo->db, d);
679 g_mutex_unlock(_mapdb_mutex);
681 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists);
686 mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
689 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
690 repo->name, zoom, tilex, tiley);
691 g_mutex_lock(_mapdb_mutex);
692 pixbuf = map_cache_get(repo, zoom, tilex, tiley);
693 g_mutex_unlock(_mapdb_mutex);
694 vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf);
700 mapdb_checkdec(RepoData *repo, gint zoom, gint tilex, gint tiley)
702 gboolean success = TRUE;
703 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
704 repo->name, zoom, tilex, tiley);
706 /* First, we have to check if the old map was a dup. */
707 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
708 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
709 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
710 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)
711 && sqlite3_column_bytes(repo->stmt_map_select, 0)
712 <= MAX_PIXBUF_DUP_SIZE)
714 /* Old map was indeed a dup. Decrement the reference count. */
715 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
716 if(SQLITE_OK != sqlite3_bind_int(
717 repo->stmt_dup_decrem, 1, hash)
718 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_decrem)
719 || SQLITE_OK != sqlite3_bind_int(
720 repo->stmt_dup_delete, 1, hash)
721 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_delete))
724 printf("Error in stmt_dup_decrem: %s\n",
725 sqlite3_errmsg(repo->db));
727 sqlite3_reset(repo->stmt_dup_delete);
728 sqlite3_reset(repo->stmt_dup_decrem);
730 sqlite3_reset(repo->stmt_map_select);
732 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
738 mapdb_update(gboolean exists, RepoData *repo,
739 gint zoom, gint tilex, gint tiley, void *bytes, gint size)
746 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
747 repo->name, zoom, tilex, tiley);
749 g_mutex_lock(_mapdb_mutex);
750 map_cache_update(repo, zoom, tilex, tiley, bytes, size);
754 /* There is no cache. Return FALSE. */
755 g_mutex_unlock(_mapdb_mutex);
756 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
761 /* At least try to open a transaction. */
762 sqlite3_step(repo->stmt_trans_begin);
763 sqlite3_reset(repo->stmt_trans_begin);
765 /* Pixbufs of size MAX_PIXBUF_DUP_SIZE or less are special. They are
766 * probably PNGs of a single color (like blue for water or beige for empty
767 * land). To reduce redundancy in the database, we will store them in a
768 * separate table and, in the maps table, only refer to them. */
769 if(size <= MAX_PIXBUF_DUP_SIZE)
771 /* Duplicate pixbuf. */
774 /* First, check if we need to remove a count from the dups table.*/
775 mapdb_checkdec(repo, zoom, tilex, tiley);
779 /* Compute hash of the bytes. */
780 gchar *cur = bytes, *end = bytes + size;
783 hash = (hash << 5) - hash + *(++cur);
785 /* Check if dup already exists. */
786 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_exists, 1, hash)
787 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_exists)
788 && sqlite3_column_int(repo->stmt_dup_exists, 0) > 0)
790 /* Dup already exists - increment existing entry. */
791 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_increm,1, hash)
792 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_increm))
795 printf("Error in stmt_dup_increm: %s\n",
796 sqlite3_errmsg(repo->db));
798 sqlite3_reset(repo->stmt_dup_increm);
802 /* Dup doesn't exist - add new entry. */
803 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_insert,1, hash)
804 || SQLITE_OK != sqlite3_bind_blob(repo->stmt_dup_insert,
805 2, bytes, size, NULL)
806 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_insert))
809 printf("Error in stmt_dup_insert: %s\n",
810 sqlite3_errmsg(repo->db));
812 sqlite3_reset(repo->stmt_dup_insert);
814 sqlite3_reset(repo->stmt_dup_exists);
816 /* Now, if successful so far, we fall through the end of this if
817 * statement and insert the hash as the blob. Setting bytes to NULL
818 * is the signal to do this. */
824 stmt = exists ? repo->stmt_map_update : repo->stmt_map_insert;
826 /* Attempt to insert map from database. */
827 if(SQLITE_OK != (bytes ? sqlite3_bind_blob(stmt, 1, bytes, size, NULL)
828 : sqlite3_bind_int(stmt, 1, hash))
829 || SQLITE_OK != sqlite3_bind_int(stmt, 2, zoom)
830 || SQLITE_OK != sqlite3_bind_int(stmt, 3, tilex)
831 || SQLITE_OK != sqlite3_bind_int(stmt, 4, tiley)
832 || SQLITE_DONE != sqlite3_step(stmt))
835 printf("Error in mapdb_update: %s\n", sqlite3_errmsg(repo->db));
842 sqlite3_step(repo->stmt_trans_commit);
843 sqlite3_reset(repo->stmt_trans_commit);
847 sqlite3_step(repo->stmt_trans_rollback);
848 sqlite3_reset(repo->stmt_trans_rollback);
859 dkey.dptr = (gchar*)&key;
860 dkey.dsize = sizeof(key);
863 success = !gdbm_store(repo->db, dkey, dcon, GDBM_REPLACE);
866 g_mutex_unlock(_mapdb_mutex);
868 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
873 mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley)
875 gint success = FALSE;
876 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
877 repo->name, zoom, tilex, tiley);
879 g_mutex_lock(_mapdb_mutex);
880 map_cache_remove(repo, zoom, tilex, tiley);
884 /* There is no cache. Return FALSE. */
885 g_mutex_unlock(_mapdb_mutex);
886 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
891 /* At least try to open a transaction. */
892 sqlite3_step(repo->stmt_trans_begin);
893 sqlite3_reset(repo->stmt_trans_begin);
895 /* First, check if we need to remove a count from the dups table. */
896 /* Then, attempt to delete map from database. */
897 if(!mapdb_checkdec(repo, zoom, tilex, tiley)
898 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 1, zoom)
899 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 2, tilex)
900 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 3, tiley)
901 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
904 printf("Error in stmt_map_delete: %s\n",
905 sqlite3_errmsg(repo->db));
907 sqlite3_reset(repo->stmt_map_delete);
911 sqlite3_step(repo->stmt_trans_commit);
912 sqlite3_reset(repo->stmt_trans_commit);
916 sqlite3_step(repo->stmt_trans_rollback);
917 sqlite3_reset(repo->stmt_trans_rollback);
927 d.dptr = (gchar*)&key;
928 d.dsize = sizeof(key);
929 success = !gdbm_delete(repo->db, d);
932 g_mutex_unlock(_mapdb_mutex);
934 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
939 set_repo_type(RepoData *repo)
941 printf("%s(%s)\n", __PRETTY_FUNCTION__, repo->url);
943 if(repo->url && *repo->url)
945 gchar *url = g_utf8_strdown(repo->url, -1);
947 /* Determine type of repository. */
948 if(strstr(url, "service=wms"))
949 repo->type = REPOTYPE_WMS;
950 else if(strstr(url, "%s"))
951 repo->type = REPOTYPE_QUAD_QRST;
952 else if(strstr(url, "%0d"))
953 repo->type = REPOTYPE_XYZ_INV;
954 else if(strstr(url, "%-d"))
955 repo->type = REPOTYPE_XYZ_SIGNED;
956 else if(strstr(url, "%0s"))
957 repo->type = REPOTYPE_QUAD_ZERO;
959 repo->type = REPOTYPE_XYZ;
964 repo->type = REPOTYPE_NONE;
966 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
969 /* Returns the directory containing the given database filename, or NULL
970 * if the database file could not be created. */
972 repo_make_db(RepoData *rd)
974 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
978 db_dirname = g_path_get_dirname(rd->db_filename);
980 /* Check if db_filename is a directory and ask to upgrade. */
981 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
983 gchar buffer[BUFFER_SIZE];
984 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
985 g_free(rd->db_filename);
986 rd->db_filename = new_name;
988 snprintf(buffer, sizeof(buffer), "%s",
989 _("The current repository is in a legacy format and will "
990 "be converted. You should delete your old maps if you "
991 "no longer plan to use them."));
992 popup_error(_window, buffer);
995 if(g_mkdir_with_parents(db_dirname, 0755))
1002 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
1004 fd = g_creat(rd->db_filename, 0644);
1013 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
1014 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
1015 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
1019 repo_set_curr(RepoData *rd)
1023 printf("%s()\n", __PRETTY_FUNCTION__);
1024 if(!rd->db_filename || !*rd->db_filename
1025 || repo_make_db(rd))
1027 repo_p = _curr_repo;
1033 g_mutex_lock(_mapdb_mutex);
1035 sqlite3_close(repo_p->db);
1038 gdbm_close(repo_p->db);
1041 g_mutex_unlock(_mapdb_mutex);
1043 repo_p = repo_p->layers;
1046 /* Set the current repository! */
1049 /* Set up the database. */
1050 if(_curr_repo->db_filename && *_curr_repo->db_filename)
1054 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
1056 /* Open worked. Now create tables, failing if they already exist.*/
1057 || (sqlite3_exec(_curr_repo->db,
1058 "create table maps ("
1063 "primary key (zoom, tilex, tiley))"
1065 "create table dups ("
1066 "hash integer primary key, "
1069 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
1070 /* Prepare select map statement. */
1071 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1072 "select pixbuf from maps "
1073 "where zoom = ? and tilex = ? and tiley = ?",
1074 -1, &_curr_repo->stmt_map_select, NULL)
1075 /* Prepare exists map statement. */
1076 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1077 "select count(*) from maps "
1078 "where zoom = ? and tilex = ? and tiley = ?",
1079 -1, &_curr_repo->stmt_map_exists, NULL)
1080 /* Prepare insert map statement. */
1081 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1082 "insert into maps (pixbuf, zoom, tilex, tiley)"
1083 " values (?, ?, ?, ?)",
1084 -1, &_curr_repo->stmt_map_insert, NULL)
1085 /* Prepare update map statement. */
1086 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1087 "update maps set pixbuf = ? "
1088 "where zoom = ? and tilex = ? and tiley = ?",
1089 -1, &_curr_repo->stmt_map_update, NULL)
1090 /* Prepare delete map statement. */
1091 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1093 "where zoom = ? and tilex = ? and tiley = ?",
1094 -1, &_curr_repo->stmt_map_delete, NULL)
1096 /* Prepare select-by-map dup statement. */
1097 /* Prepare select-by-hash dup statement. */
1098 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1099 "select pixbuf from dups "
1101 -1, &_curr_repo->stmt_dup_select, NULL)
1102 /* Prepare exists map statement. */
1103 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1104 "select count(*) from dups "
1106 -1, &_curr_repo->stmt_dup_exists, NULL)
1107 /* Prepare insert dup statement. */
1108 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1109 "insert into dups (hash, pixbuf, uses) "
1111 -1, &_curr_repo->stmt_dup_insert, NULL)
1112 /* Prepare increment dup statement. */
1113 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1115 "set uses = uses + 1 "
1117 -1, &_curr_repo->stmt_dup_increm, NULL)
1118 /* Prepare decrement dup statement. */
1119 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1121 "set uses = uses - 1 "
1123 -1, &_curr_repo->stmt_dup_decrem, NULL)
1124 /* Prepare delete dup statement. */
1125 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1127 "where hash = ? and uses <= 0",
1128 -1, &_curr_repo->stmt_dup_delete, NULL)
1130 /* Prepare begin-transaction statement. */
1131 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1132 "begin transaction",
1133 -1, &_curr_repo->stmt_trans_begin, NULL)
1134 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1135 "commit transaction",
1136 -1, &_curr_repo->stmt_trans_commit, NULL)
1137 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1138 "rollback transaction", -1,
1139 &_curr_repo->stmt_trans_rollback, NULL))
1141 gchar buffer[BUFFER_SIZE];
1142 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
1143 _("Failed to open map database for repository"),
1144 sqlite3_errmsg(_curr_repo->db),
1145 _("Downloaded maps will not be cached."));
1146 sqlite3_close(_curr_repo->db);
1147 _curr_repo->db = NULL;
1148 popup_error(_window, buffer);
1151 /* initialize all databases for all layers */
1152 repo_p = _curr_repo;
1154 if (repo_p->db_filename && *repo_p->db_filename
1155 && repo_make_db (repo_p))
1156 repo_p->db = gdbm_open(repo_p->db_filename,
1157 0, GDBM_WRCREAT | GDBM_FAST, 0644, NULL);
1158 repo_p = repo_p->layers;
1163 gchar buffer[BUFFER_SIZE];
1164 snprintf(buffer, sizeof(buffer), "%s\n%s",
1165 _("Failed to open map database for repository"),
1166 _("Downloaded maps will not be cached."));
1167 _curr_repo->db = NULL;
1168 popup_error(_window, buffer);
1174 _curr_repo->db = NULL;
1176 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1181 gchar buffer[BUFFER_SIZE];
1182 snprintf(buffer, sizeof(buffer), "%s: %s",
1183 _("Unable to create map database for repository"), rd->name);
1184 popup_error(_window, buffer);
1186 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1194 * 1. base == layer, or
1195 * 2. layer is sublayer of base
1197 gboolean repo_is_layer (RepoData* base, RepoData* layer)
1202 base = base->layers;
1210 * Given a wms uri pattern, compute the coordinate transformation and
1212 * 'proj' is used for the conversion
1215 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
1217 gint system_retcode;
1218 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
1221 gdouble lon1, lat1, lon2, lat2;
1223 gchar *widthstr = strcasestr(uri,"WIDTH=");
1224 gchar *heightstr = strcasestr(uri,"HEIGHT=");
1225 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
1226 gchar *srsstre = strchr(srsstr,'&');
1227 vprintf("%s()\n", __PRETTY_FUNCTION__);
1229 /* missing: test if found */
1231 strncpy(srs+4,srsstr+8,256);
1232 /* missing: test srsstre-srsstr < 526 */
1233 srs[srsstre-srsstr-4] = 0;
1234 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
1236 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
1237 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
1239 unit2latlon(tile2zunit(tilex,zoomlevel)
1240 - pixel2zunit(dwidth/2,zoomlevel),
1241 tile2zunit(tiley+1,zoomlevel)
1242 + pixel2zunit((dheight+1)/2,zoomlevel),
1245 unit2latlon(tile2zunit(tilex+1,zoomlevel)
1246 + pixel2zunit((dwidth+1)/2,zoomlevel),
1247 tile2zunit(tiley,zoomlevel)
1248 - pixel2zunit(dheight/2,zoomlevel),
1251 setlocale(LC_NUMERIC, "C");
1253 snprintf(cmd, sizeof(cmd),
1254 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
1255 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
1256 " > /tmp/tmpcs2cs ",
1257 lon1, lat1, lon2, lat2, srs);
1258 vprintf("Running command: %s\n", cmd);
1259 system_retcode = system(cmd);
1262 g_printerr("cs2cs returned error code %d\n",
1263 WEXITSTATUS(system_retcode));
1264 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
1265 g_printerr("Cannot open results of conversion\n");
1266 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
1267 &lon1, &lat1, cmd, &lon2, &lat2))
1269 g_printerr("Wrong conversion\n");
1275 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
1278 setlocale(LC_NUMERIC, "");
1280 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
1286 * Given the xyz coordinates of our map coordinate system, write the qrst
1287 * quadtree coordinates to buffer.
1290 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
1291 gchar *buffer, const gchar initial,
1292 const gchar *const quadrant)
1294 gchar *ptr = buffer;
1296 vprintf("%s()\n", __PRETTY_FUNCTION__);
1301 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
1303 gint xbit = (x >> n) & 1;
1304 gint ybit = (y >> n) & 1;
1305 *ptr++ = quadrant[xbit + 2 * ybit];
1308 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1312 * Construct the URL that we should fetch, based on the current URI format.
1313 * This method works differently depending on if a "%s" string is present in
1314 * the URI format, since that would indicate a quadtree-based map coordinate
1318 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
1321 vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1322 repo, zoom, tilex, tiley);
1326 retval = g_strdup_printf(repo->url,
1327 tilex, tiley, zoom - (MAX_ZOOM - 16));
1330 case REPOTYPE_XYZ_INV:
1331 retval = g_strdup_printf(repo->url,
1332 MAX_ZOOM + 1 - zoom, tilex, tiley);
1335 case REPOTYPE_XYZ_SIGNED:
1336 retval = g_strdup_printf(repo->url,
1338 (1 << (MAX_ZOOM - zoom)) - tiley - 1,
1339 zoom - (MAX_ZOOM - 17));
1342 case REPOTYPE_QUAD_QRST:
1344 gchar location[MAX_ZOOM + 2];
1345 map_convert_coords_to_quadtree_string(
1346 tilex, tiley, zoom, location, 't', "qrts");
1347 retval = g_strdup_printf(repo->url, location);
1351 case REPOTYPE_QUAD_ZERO:
1353 /* This is a zero-based quadtree URI. */
1354 gchar location[MAX_ZOOM + 2];
1355 map_convert_coords_to_quadtree_string(
1356 tilex, tiley, zoom, location, '\0', "0123");
1357 retval = g_strdup_printf(repo->url, location);
1362 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
1366 retval = g_strdup(repo->url);
1369 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
1374 mapdb_initiate_update_banner_idle()
1376 if(!_download_banner && _num_downloads != _curr_download)
1378 _download_banner = hildon_banner_show_progress(
1379 _window, NULL, _("Processing Maps"));
1380 /* If we're not connected, then hide the banner immediately. It will
1381 * be unhidden if/when we're connected. */
1382 if(!_conic_is_connected)
1383 gtk_widget_hide(_download_banner);
1389 * Initiate a download of the given xyz coordinates using the given buffer
1390 * as the URL. If the map already exists on disk, or if we are already
1391 * downloading the map, then this method does nothing.
1394 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
1395 gint update_type, gint batch_id, gint priority,
1396 ThreadLatch *refresh_latch)
1399 MapUpdateTask *old_mut;
1400 gboolean is_replacing = FALSE;
1401 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1402 repo->name, zoom, tilex, tiley, update_type);
1404 mut = g_slice_new(MapUpdateTask);
1407 /* Could not allocate memory. */
1408 g_printerr("Out of memory in allocation of update task #%d\n",
1409 _num_downloads + 1);
1415 mut->update_type = update_type;
1416 mut->layer_level = repo->layer_level;
1418 /* Lock the mutex if this is an auto-update. */
1419 if(update_type == MAP_UPDATE_AUTO)
1420 g_mutex_lock(_mut_priority_mutex);
1421 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
1423 /* Check if new mut is in a newer batch that the old mut.
1424 * We use vfs_result to indicate a MUT that is already in the process
1425 * of being downloaded. */
1426 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
1428 /* It is, so remove the old one so we can re-add this one. */
1429 g_hash_table_remove(_mut_exists_table, old_mut);
1430 g_tree_remove(_mut_priority_tree, old_mut);
1431 g_slice_free(MapUpdateTask, old_mut);
1432 is_replacing = TRUE;
1436 /* It's not, so just ignore it. */
1437 if(update_type == MAP_UPDATE_AUTO)
1438 g_mutex_unlock(_mut_priority_mutex);
1439 g_slice_free(MapUpdateTask, mut);
1440 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
1445 g_hash_table_insert(_mut_exists_table, mut, mut);
1448 mut->refresh_latch = refresh_latch;
1449 mut->priority = priority;
1450 mut->batch_id = batch_id;
1452 mut->vfs_result = -1;
1454 g_tree_insert(_mut_priority_tree, mut, mut);
1456 /* Unlock the mutex if this is an auto-update. */
1457 if(update_type == MAP_UPDATE_AUTO)
1458 g_mutex_unlock(_mut_priority_mutex);
1462 /* Increment download count and (possibly) display banner. */
1463 if(++_num_downloads == 20 && !_download_banner)
1464 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
1466 /* This doesn't need to be thread-safe. Extras in the pool don't
1467 * really make a difference. */
1468 if(g_thread_pool_get_num_threads(_mut_thread_pool)
1469 < g_thread_pool_get_max_threads(_mut_thread_pool))
1470 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1473 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1478 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1487 printf("%s()\n", __PRETTY_FUNCTION__);
1489 /* Make sure things are inititalized. */
1492 while(conic_ensure_connected())
1495 gboolean refresh_sent = FALSE, layer_tile;
1496 MapUpdateTask *mut = NULL;
1498 /* Get the next MUT from the mut tree. */
1499 g_mutex_lock(_mut_priority_mutex);
1500 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1503 /* No more MUTs to process. Return. */
1504 g_mutex_unlock(_mut_priority_mutex);
1507 /* Mark this MUT as "in-progress". */
1508 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1509 g_tree_remove(_mut_priority_tree, mut);
1510 g_mutex_unlock(_mut_priority_mutex);
1512 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1513 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1515 layer_tile = mut->repo != _curr_repo && repo_is_layer (_curr_repo, mut->repo);
1517 if (mut->repo != _curr_repo && !layer_tile)
1519 /* Do nothing, except report that there is no error. */
1520 mut->vfs_result = GNOME_VFS_OK;
1522 else if(mut->update_type == MAP_UPDATE_DELETE)
1524 /* Easy - just delete the entry from the database. We don't care
1525 * about failures (sorry). */
1527 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1529 /* Report that there is no error. */
1530 mut->vfs_result = GNOME_VFS_OK;
1532 else for(retries = mut->repo->layer_level ? 1 : INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1534 gboolean exists = FALSE;
1538 GdkPixbufLoader *loader;
1540 gint zoom, tilex, tiley;
1541 GError *error = NULL;
1544 /* First check for existence. */
1545 exists = mut->repo->db
1546 ? mapdb_exists(mut->repo, mut->zoom,
1547 mut->tilex, mut->tiley)
1549 if(exists && mut->update_type == MAP_UPDATE_ADD)
1551 /* Map already exists, and we're not going to overwrite. */
1552 /* Report that there is no error. */
1553 mut->vfs_result = GNOME_VFS_OK;
1557 /* First check for existence. */
1558 if(mut->update_type == MAP_UPDATE_ADD)
1560 /* We don't want to overwrite, so check for existence. */
1561 /* Map already exists, and we're not going to overwrite. */
1562 if(mapdb_exists(mut->repo, mut->zoom,
1563 mut->tilex,mut->tiley))
1565 /* Report that there is no error. */
1566 mut->vfs_result = GNOME_VFS_OK;
1572 /* First, construct the URL from which we will get the data. */
1573 src_url = map_construct_url(mut->repo, mut->zoom,
1574 mut->tilex, mut->tiley);
1576 /* Now, attempt to read the entire contents of the URL. */
1577 mut->vfs_result = gnome_vfs_read_entire_file(
1578 src_url, &size, &bytes);
1580 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1583 printf("Error reading URL: %s\n",
1584 gnome_vfs_result_to_string(mut->vfs_result));
1588 /* usleep(100000); DEBUG */
1590 /* Attempt to parse the bytes into a pixbuf. */
1591 loader = gdk_pixbuf_loader_new();
1592 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1593 gdk_pixbuf_loader_close(loader, &error);
1594 if(error || (NULL == (mut->pixbuf = g_object_ref(
1595 gdk_pixbuf_loader_get_pixbuf(loader)))))
1597 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1599 g_object_unref(mut->pixbuf);
1602 g_object_unref(loader);
1603 printf("Error parsing pixbuf: %s\n",
1604 error ? error->message : "?");
1607 g_object_unref(loader);
1609 /* attach timestamp with loaded pixbuf */
1613 GError* error = NULL;
1616 sprintf (ts_val, "%u", (unsigned int)time (NULL));
1618 /* update bytes with new, timestamped pixbuf */
1619 if (gdk_pixbuf_save_to_buffer (mut->pixbuf, &new_bytes, &new_size, "png", &error, layer_timestamp_key, ts_val, NULL))
1627 /* Copy database-relevant mut data before we release it. */
1633 /* Pass the mut to the GTK thread for redrawing, but only if a
1634 * redraw isn't already in the pipeline. */
1635 if(mut->refresh_latch)
1637 /* Wait until the latch is open. */
1638 g_mutex_lock(mut->refresh_latch->mutex);
1639 while(!mut->refresh_latch->is_open)
1641 g_cond_wait(mut->refresh_latch->cond,
1642 mut->refresh_latch->mutex);
1644 /* Latch is open. Decrement the number of waiters and
1645 * check if we're the last waiter to run. */
1646 if(mut->refresh_latch->is_done_adding_tasks)
1648 if(++mut->refresh_latch->num_done
1649 == mut->refresh_latch->num_tasks)
1651 /* Last waiter. Free the latch resources. */
1652 g_mutex_unlock(mut->refresh_latch->mutex);
1653 g_cond_free(mut->refresh_latch->cond);
1654 g_mutex_free(mut->refresh_latch->mutex);
1655 g_slice_free(ThreadLatch, mut->refresh_latch);
1656 mut->refresh_latch = NULL;
1660 /* Not the last waiter. Signal the next waiter.*/
1661 g_cond_signal(mut->refresh_latch->cond);
1662 g_mutex_unlock(mut->refresh_latch->mutex);
1666 g_mutex_unlock(mut->refresh_latch->mutex);
1669 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1670 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1671 refresh_sent = TRUE;
1673 /* DO NOT USE mut FROM THIS POINT ON. */
1675 /* Also attempt to add to the database. */
1676 mapdb_update(exists, repo, zoom,
1677 tilex, tiley, bytes, size);
1685 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1686 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1689 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1694 mut_exists_hashfunc(const MapUpdateTask *a)
1696 gint sum = a->zoom + a->tilex + a->tiley + a->update_type + a->layer_level;
1697 return g_int_hash(&sum);
1701 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1703 return (a->tilex == b->tilex
1704 && a->tiley == b->tiley
1705 && a->zoom == b->zoom
1706 && a->update_type == b->update_type
1707 && a->layer_level == b->layer_level);
1711 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1713 /* The update_type enum is sorted in order of ascending priority. */
1714 gint diff = (b->update_type - a->update_type);
1717 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1720 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1723 diff = (a->layer_level - b->layer_level); /* Lower layers first. */
1727 /* At this point, we don't care, so just pick arbitrarily. */
1728 diff = (a->tilex - b->tilex);
1731 diff = (a->tiley - b->tiley);
1734 return (a->zoom - b->zoom);
1738 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1740 printf("%s()\n", __PRETTY_FUNCTION__);
1741 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1742 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1743 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1748 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1752 printf("%s()\n", __PRETTY_FUNCTION__);
1754 dialog = GTK_WIDGET(
1755 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1756 GTK_FILE_CHOOSER_ACTION_SAVE));
1758 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1759 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1761 /* Work around a bug in HildonFileChooserDialog. */
1762 basename = g_path_get_basename(
1763 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1764 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1765 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1767 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1769 gchar *filename = gtk_file_chooser_get_filename(
1770 GTK_FILE_CHOOSER(dialog));
1771 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1775 gtk_widget_destroy(dialog);
1777 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1782 repoman_compact_complete_idle(CompactInfo *ci)
1784 printf("%s()\n", __PRETTY_FUNCTION__);
1786 gtk_widget_destroy(GTK_WIDGET(ci->banner));
1787 popup_error(ci->dialog, ci->status_msg);
1788 gtk_widget_destroy(ci->dialog);
1791 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1796 thread_repoman_compact(CompactInfo *ci)
1799 printf("%s()\n", __PRETTY_FUNCTION__);
1801 if(!(db = gdbm_open((gchar*)ci->db_filename, 0, GDBM_WRITER | GDBM_FAST,
1803 ci->status_msg = _("Failed to open map database for compacting.");
1806 if(gdbm_reorganize(db))
1807 ci->status_msg = _("An error occurred while trying to "
1808 "compact the database.");
1810 ci->status_msg = _("Successfully compacted database.");
1814 g_idle_add((GSourceFunc)repoman_compact_complete_idle, ci);
1816 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1820 repoman_dialog_compact(GtkWidget *widget, BrowseInfo *browse_info)
1824 printf("%s()\n", __PRETTY_FUNCTION__);
1826 ci = g_new0(CompactInfo, 1);
1828 ci->dialog = gtk_dialog_new_with_buttons(_("Compact Database"),
1829 GTK_WINDOW(browse_info->dialog), GTK_DIALOG_MODAL,
1830 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1831 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1834 sw = gtk_scrolled_window_new (NULL, NULL);
1835 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1836 GTK_SHADOW_ETCHED_IN);
1837 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1840 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ci->dialog)->vbox),
1843 gtk_container_add(GTK_CONTAINER(sw), ci->txt = gtk_text_view_new());
1844 gtk_text_view_set_editable(GTK_TEXT_VIEW(ci->txt), FALSE);
1845 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ci->txt), FALSE);
1846 gtk_text_buffer_set_text(
1847 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1848 _("Generally, deleted maps create an empty space in the "
1849 "database that is later reused when downloading new maps. "
1850 "Compacting the database reorganizes it such that all "
1851 "that blank space is eliminated. This is the only way "
1852 "that the size of the database can decrease.\n"
1853 "This reorganization requires creating a new file and "
1854 "inserting all the maps in the old database file into the "
1855 "new file. The new file is then renamed to the same name "
1856 "as the old file and dbf is updated to contain all the "
1857 "correct information about the new file. Note that this "
1858 "can require free space on disk of an amount up to the size "
1859 "of the map database.\n"
1860 "This process may take several minutes, especially if "
1861 "your map database is large. As a rough estimate, you can "
1862 "expect to wait approximately 2-5 seconds per megabyte of "
1863 "map data (34-85 minutes per gigabyte). There is no progress "
1864 "indicator, although you can watch the new file grow in any "
1865 "file manager. Do not attempt to close Maemo Mapper while "
1866 "the compacting operation is in progress."),
1870 gtk_text_buffer_get_iter_at_offset(
1871 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1873 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ci->txt),
1874 &iter, 0.0, FALSE, 0, 0);
1877 gtk_widget_set_size_request(GTK_WIDGET(sw), 600, 200);
1878 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(ci->txt), GTK_WRAP_WORD);
1880 gtk_widget_show_all(ci->dialog);
1882 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(ci->dialog)))
1884 gtk_widget_set_sensitive(GTK_DIALOG(ci->dialog)->action_area, FALSE);
1885 ci->db_filename = gtk_entry_get_text(GTK_ENTRY(browse_info->txt));
1886 ci->banner = hildon_banner_show_animation(ci->dialog, NULL,
1887 _("Compacting database..."));
1889 g_thread_create((GThreadFunc)thread_repoman_compact, ci, FALSE, NULL);
1893 gtk_widget_destroy(ci->dialog);
1896 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1900 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1902 static GtkWidget *hbox = NULL;
1903 static GtkWidget *label = NULL;
1904 static GtkWidget *txt_name = NULL;
1905 static GtkWidget *dialog = NULL;
1906 printf("%s()\n", __PRETTY_FUNCTION__);
1910 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1911 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1912 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1913 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1916 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1917 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1919 gtk_box_pack_start(GTK_BOX(hbox),
1920 label = gtk_label_new(_("Name")),
1922 gtk_box_pack_start(GTK_BOX(hbox),
1923 txt_name = gtk_entry_new(),
1928 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1929 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1930 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1933 gtk_widget_show_all(dialog);
1935 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1937 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1938 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1940 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1941 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1942 active, g_strdup(rei->name));
1943 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1944 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1948 gtk_widget_hide(dialog);
1950 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1955 repoman_delete(RepoManInfo *rmi, gint index)
1957 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1958 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1959 rmi->repo_edits = g_list_remove_link(
1961 g_list_nth(rmi->repo_edits, index));
1965 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1969 printf("%s()\n", __PRETTY_FUNCTION__);
1971 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1972 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1975 popup_error(rmi->dialog,
1976 _("Cannot delete the last repository - there must be at"
1977 " lease one repository."));
1978 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1982 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1983 _("Confirm delete of repository"),
1984 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1986 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1988 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1990 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1991 repoman_delete(rmi, active);
1992 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1996 gtk_widget_destroy(confirm);
2001 static RepoEditInfo*
2002 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
2008 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
2009 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
2014 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
2015 vbox = gtk_vbox_new(FALSE, 4),
2016 gtk_label_new(name));
2018 /* Prevent destruction of notebook page, because the destruction causes
2019 * a seg fault (!?!?) */
2020 gtk_object_ref(GTK_OBJECT(vbox));
2022 gtk_box_pack_start(GTK_BOX(vbox),
2023 table = gtk_table_new(2, 2, FALSE),
2025 /* Map download URI. */
2026 gtk_table_attach(GTK_TABLE(table),
2027 label = gtk_label_new(_("URL Format")),
2028 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2029 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2030 gtk_table_attach(GTK_TABLE(table),
2031 rei->txt_url = gtk_entry_new(),
2032 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2034 /* Map Directory. */
2035 gtk_table_attach(GTK_TABLE(table),
2036 label = gtk_label_new(_("Cache DB")),
2037 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2038 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2039 gtk_table_attach(GTK_TABLE(table),
2040 hbox = gtk_hbox_new(FALSE, 4),
2041 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2042 gtk_box_pack_start(GTK_BOX(hbox),
2043 rei->txt_db_filename = gtk_entry_new(),
2045 gtk_box_pack_start(GTK_BOX(hbox),
2046 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
2048 gtk_box_pack_start(GTK_BOX(hbox),
2049 rei->btn_compact = gtk_button_new_with_label(_("Compact...")),
2052 /* Initialize cache dir */
2054 gchar buffer[BUFFER_SIZE];
2055 snprintf(buffer, sizeof(buffer), "%s.db", name);
2056 gchar *db_base = gnome_vfs_expand_initial_tilde(
2057 REPO_DEFAULT_CACHE_BASE);
2058 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
2060 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
2061 g_free(db_filename);
2065 gtk_box_pack_start(GTK_BOX(vbox),
2066 table = gtk_table_new(3, 2, FALSE),
2069 /* Download Zoom Steps. */
2070 gtk_table_attach(GTK_TABLE(table),
2071 label = gtk_label_new(_("Download Zoom Steps")),
2072 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2073 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2074 gtk_table_attach(GTK_TABLE(table),
2075 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2076 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
2077 gtk_container_add(GTK_CONTAINER(label),
2078 rei->num_dl_zoom_steps = hildon_controlbar_new());
2079 hildon_controlbar_set_range(
2080 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
2081 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2082 REPO_DEFAULT_DL_ZOOM_STEPS);
2083 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
2085 /* Download Zoom Steps. */
2086 gtk_table_attach(GTK_TABLE(table),
2087 label = gtk_label_new(_("View Zoom Steps")),
2088 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2089 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2090 gtk_table_attach(GTK_TABLE(table),
2091 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2092 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
2093 gtk_container_add(GTK_CONTAINER(label),
2094 rei->num_view_zoom_steps = hildon_controlbar_new());
2095 hildon_controlbar_set_range(
2096 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
2097 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2098 REPO_DEFAULT_VIEW_ZOOM_STEPS);
2099 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
2101 gtk_table_attach(GTK_TABLE(table),
2102 label = gtk_vseparator_new(),
2103 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
2106 gtk_table_attach(GTK_TABLE(table),
2107 rei->chk_double_size = gtk_check_button_new_with_label(
2108 _("Double Pixels")),
2109 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
2110 gtk_toggle_button_set_active(
2111 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
2114 gtk_table_attach(GTK_TABLE(table),
2115 rei->chk_nextable = gtk_check_button_new_with_label(
2117 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
2118 gtk_toggle_button_set_active(
2119 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
2121 /* Downloadable Zoom Levels. */
2122 gtk_table_attach(GTK_TABLE(table),
2123 label = gtk_label_new(_("Downloadable Zooms:")),
2124 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2125 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2126 gtk_table_attach(GTK_TABLE(table),
2127 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2128 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
2129 gtk_container_add(GTK_CONTAINER(label),
2130 hbox = gtk_hbox_new(FALSE, 4));
2131 gtk_box_pack_start(GTK_BOX(hbox),
2132 label = gtk_label_new(_("Min.")),
2134 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2135 gtk_box_pack_start(GTK_BOX(hbox),
2136 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2138 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
2139 gtk_box_pack_start(GTK_BOX(hbox),
2140 label = gtk_label_new(""),
2142 gtk_box_pack_start(GTK_BOX(hbox),
2143 label = gtk_label_new(_("Max.")),
2145 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2146 gtk_box_pack_start(GTK_BOX(hbox),
2147 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2149 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
2151 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
2153 /* Connect signals. */
2154 rei->browse_info.dialog = rmi->dialog;
2155 rei->browse_info.txt = rei->txt_db_filename;
2156 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
2157 G_CALLBACK(repoman_dialog_browse),
2159 g_signal_connect(G_OBJECT(rei->btn_compact), "clicked",
2160 G_CALLBACK(repoman_dialog_compact),
2163 gtk_widget_show_all(vbox);
2165 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
2166 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
2167 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
2168 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
2171 /* newly created repos keep this NULL in rei, indicating
2172 that layes cannot be added so far */
2175 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2180 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
2182 static GtkWidget *hbox = NULL;
2183 static GtkWidget *label = NULL;
2184 static GtkWidget *txt_name = NULL;
2185 static GtkWidget *dialog = NULL;
2186 printf("%s()\n", __PRETTY_FUNCTION__);
2190 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
2191 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
2192 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2193 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2196 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2197 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2199 gtk_box_pack_start(GTK_BOX(hbox),
2200 label = gtk_label_new(_("Name")),
2202 gtk_box_pack_start(GTK_BOX(hbox),
2203 txt_name = gtk_entry_new(),
2207 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2209 gtk_widget_show_all(dialog);
2211 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2213 repoman_dialog_add_repo(rmi,
2214 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2218 gtk_widget_hide(dialog);
2220 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2225 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
2228 printf("%s()\n", __PRETTY_FUNCTION__);
2230 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
2231 _("Replace all repositories with the default repository?"));
2233 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2235 /* First, delete all existing repositories. */
2236 while(rmi->repo_edits)
2237 repoman_delete(rmi, 0);
2239 /* Now, add the default repository. */
2240 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
2242 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
2243 REPO_DEFAULT_MAP_URI);
2245 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
2247 gtk_widget_destroy(confirm);
2249 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2257 printf("%s()\n", __PRETTY_FUNCTION__);
2259 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
2260 _("Maemo Mapper will now download and add a list of "
2261 "possibly-duplicate repositories from the internet. "
2264 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2270 GnomeVFSResult vfs_result;
2271 printf("%s()\n", __PRETTY_FUNCTION__);
2273 /* Get repo config file from www.gnuite.com. */
2274 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2275 "http://www.gnuite.com/nokia770/maemo-mapper/"
2276 "repos-with-layers.txt",
2279 popup_error(_window,
2280 _("An error occurred while retrieving the repositories. "
2281 "The web service may be temporarily down."));
2282 g_printerr("Error while download repositories: %s\n",
2283 gnome_vfs_result_to_string(vfs_result));
2285 /* Parse each line as a reposotory. */
2288 RepoData *prev_repo = NULL;
2289 menu_maps_remove_repos();
2290 for(head = bytes; head && *head; head = tail)
2293 tail = strchr(head, '\n');
2296 rd = settings_parse_repo(head);
2297 if (rd->layer_level == 0) {
2298 _repo_list = g_list_append(_repo_list, rd);
2301 prev_repo->layers = rd;
2306 menu_maps_add_repos();
2310 gtk_widget_destroy(confirm);
2312 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2318 layer_get_page_index (RepoLayersInfo *rli, GtkTreeIter list_it)
2320 GtkTreePath *p1, *p2;
2324 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rli->layers_store), &p);
2326 p1 = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &list_it);
2327 p2 = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &p);
2329 while (gtk_tree_path_compare (p1, p2) != 0) {
2330 gtk_tree_path_next (p2);
2334 gtk_tree_path_free (p1);
2335 gtk_tree_path_free (p2);
2342 layer_name_changed (GtkWidget *entry, LayerEditInfo *lei)
2345 GtkTreeSelection *selection;
2348 printf("%s()\n", __PRETTY_FUNCTION__);
2351 name = gtk_entry_get_text (GTK_ENTRY (entry));
2353 /* find selected entry in list view */
2354 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (lei->rli->layers_list));
2356 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2357 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2361 gtk_list_store_set (lei->rli->layers_store, &iter, 0, name, -1);
2363 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2369 layer_dialog_browse (GtkWidget *widget, LayerEditInfo *lei)
2373 printf("%s()\n", __PRETTY_FUNCTION__);
2375 dialog = GTK_WIDGET(
2376 hildon_file_chooser_dialog_new(GTK_WINDOW(lei->rli->dialog),
2377 GTK_FILE_CHOOSER_ACTION_SAVE));
2379 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
2380 gtk_entry_get_text(GTK_ENTRY(lei->txt_db)));
2382 /* Work around a bug in HildonFileChooserDialog. */
2383 basename = g_path_get_basename(
2384 gtk_entry_get_text(GTK_ENTRY(lei->txt_db)));
2385 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
2386 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
2388 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
2390 gchar *filename = gtk_file_chooser_get_filename(
2391 GTK_FILE_CHOOSER(dialog));
2392 gtk_entry_set_text(GTK_ENTRY(lei->txt_db), filename);
2396 gtk_widget_destroy(dialog);
2398 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2404 static LayerEditInfo*
2405 repoman_layers_add_layer (RepoLayersInfo *rli, gchar* name)
2407 LayerEditInfo *lei = g_new (LayerEditInfo, 1);
2412 GtkWidget *btn_browse;
2413 GtkTreeIter layers_iter;
2415 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
2419 rli->layer_edits = g_list_append (rli->layer_edits, lei);
2421 gtk_notebook_append_page (GTK_NOTEBOOK (rli->notebook), vbox = gtk_vbox_new (FALSE, 4),
2422 gtk_label_new (name));
2424 gtk_box_pack_start (GTK_BOX (vbox), table = gtk_table_new (4, 2, FALSE),
2428 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Name")),
2429 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2430 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2431 gtk_table_attach (GTK_TABLE (table), lei->txt_name = gtk_entry_new (),
2432 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2433 gtk_entry_set_text (GTK_ENTRY (lei->txt_name), name);
2436 g_signal_connect(G_OBJECT(lei->txt_name), "changed", G_CALLBACK(layer_name_changed), lei);
2439 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("URL")),
2440 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2441 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2442 gtk_table_attach (GTK_TABLE (table), lei->txt_url = gtk_entry_new (),
2443 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2446 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Cache DB")),
2447 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2448 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2449 gtk_table_attach (GTK_TABLE (table), hbox2 = gtk_hbox_new (FALSE, 4),
2450 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2451 gtk_box_pack_start (GTK_BOX (hbox2), lei->txt_db = gtk_entry_new (),
2453 gtk_box_pack_start (GTK_BOX (hbox2), btn_browse = gtk_button_new_with_label (_("Browse...")),
2456 g_signal_connect(G_OBJECT(btn_browse), "clicked", G_CALLBACK(layer_dialog_browse), lei);
2459 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Autofetch")),
2460 0, 1, 3, 4, GTK_FILL, 0, 2, 0);
2461 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2462 gtk_table_attach (GTK_TABLE (table), hbox2 = gtk_hbox_new (FALSE, 4),
2463 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2464 gtk_box_pack_start (GTK_BOX (hbox2), lei->num_autofetch = hildon_number_editor_new (0, 120),
2466 gtk_box_pack_start (GTK_BOX (hbox2), label = gtk_label_new (_("min.")), FALSE, FALSE, 4);
2467 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2470 gtk_box_pack_start (GTK_BOX (vbox), lei->chk_visible = gtk_check_button_new_with_label (_("Layer is visible")),
2473 gtk_widget_show_all (vbox);
2475 /* Side list view with layers */
2476 gtk_list_store_append (rli->layers_store, &layers_iter);
2477 gtk_list_store_set (rli->layers_store, &layers_iter, 0, name, -1);
2479 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2487 repoman_layers_new (GtkWidget *widget, RepoLayersInfo *rli)
2489 static GtkWidget *hbox = NULL;
2490 static GtkWidget *label = NULL;
2491 static GtkWidget *txt_name = NULL;
2492 static GtkWidget *dialog = NULL;
2493 printf("%s()\n", __PRETTY_FUNCTION__);
2497 dialog = gtk_dialog_new_with_buttons(_("New Layer"),
2498 GTK_WINDOW(rli->dialog), GTK_DIALOG_MODAL,
2499 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2500 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2503 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2504 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2506 gtk_box_pack_start(GTK_BOX(hbox),
2507 label = gtk_label_new(_("Name")),
2509 gtk_box_pack_start(GTK_BOX(hbox),
2510 txt_name = gtk_entry_new(),
2514 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2516 gtk_widget_show_all(dialog);
2518 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2520 repoman_layers_add_layer(rli,
2521 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2525 gtk_widget_hide(dialog);
2526 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2532 repoman_layers_del (GtkWidget *widget, RepoLayersInfo *rli)
2535 GtkTreeSelection *selection;
2538 printf("%s()\n", __PRETTY_FUNCTION__);
2540 /* delete list item */
2541 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2543 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2544 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2548 index = layer_get_page_index (rli, iter);
2549 gtk_list_store_remove (rli->layers_store, &iter);
2551 rli->layer_edits = g_list_remove_link (rli->layer_edits, g_list_nth (rli->layer_edits, index));
2553 /* delete notebook page */
2554 gtk_notebook_remove_page (GTK_NOTEBOOK (rli->notebook), index);
2556 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2562 repoman_layers_up (GtkWidget *widget, RepoLayersInfo *rli)
2564 GtkTreeSelection *selection;
2565 GtkTreeIter iter, iter2;
2571 printf("%s()\n", __PRETTY_FUNCTION__);
2573 /* find selected entry in list view */
2574 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2576 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2577 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2582 path = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &iter);
2583 if (!gtk_tree_path_prev (path) || !gtk_tree_model_get_iter (GTK_TREE_MODEL (rli->layers_store), &iter, path)) {
2584 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2588 gtk_tree_path_free (path);
2591 gtk_list_store_move_before (rli->layers_store, &iter2, &iter);
2593 /* reorder notebook tabs */
2594 page = gtk_notebook_get_current_page (GTK_NOTEBOOK (rli->notebook));
2595 gtk_notebook_reorder_child (GTK_NOTEBOOK (rli->notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (rli->notebook), page), page-1);
2597 /* reorder layer edits */
2598 list_elem = g_list_nth (rli->layer_edits, page);
2599 lei = list_elem->data;
2600 rli->layer_edits = g_list_remove_link (rli->layer_edits, list_elem);
2601 rli->layer_edits = g_list_insert (rli->layer_edits, lei, page-1);
2603 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2609 repoman_layers_dn (GtkWidget *widget, RepoLayersInfo *rli)
2611 GtkTreeSelection *selection;
2612 GtkTreeIter iter, iter2;
2617 printf("%s()\n", __PRETTY_FUNCTION__);
2619 /* find selected entry in list view */
2620 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2622 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2623 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2628 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (rli->layers_store), &iter)) {
2629 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2634 gtk_list_store_move_after (rli->layers_store, &iter2, &iter);
2636 /* reorder notebook tabs */
2637 page = gtk_notebook_get_current_page (GTK_NOTEBOOK (rli->notebook));
2638 gtk_notebook_reorder_child (GTK_NOTEBOOK (rli->notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (rli->notebook), page), page+1);
2640 /* reorder layer edits */
2641 list_elem = g_list_nth (rli->layer_edits, page);
2642 lei = list_elem->data;
2643 rli->layer_edits = g_list_remove_link (rli->layer_edits, list_elem);
2644 rli->layer_edits = g_list_insert (rli->layer_edits, lei, page+1);
2646 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2652 repoman_layer_selected (GtkTreeSelection *selection, RepoLayersInfo *rli)
2656 printf("%s()\n", __PRETTY_FUNCTION__);
2658 if (!gtk_tree_selection_get_selected (selection, NULL, &cur)) {
2659 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2663 gtk_notebook_set_current_page (GTK_NOTEBOOK (rli->notebook), layer_get_page_index (rli, cur));
2665 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2671 repoman_layers(GtkWidget *widget, RepoManInfo *rmi)
2673 GtkWidget *hbox = NULL;
2674 GtkWidget *layers_vbox = NULL;
2675 GtkWidget *buttons_hbox = NULL;
2677 GtkCellRenderer *layers_rendeder = NULL;
2678 GtkTreeViewColumn *layers_column = NULL;
2679 GtkTreeSelection *selection;
2681 /* layers buttons */
2682 GtkWidget *btn_new = NULL;
2683 GtkWidget *btn_del = NULL;
2684 GtkWidget *btn_up = NULL;
2685 GtkWidget *btn_dn = NULL;
2687 const char* t_header = _("Manage layers [%s]");
2688 char* header = NULL;
2689 RepoEditInfo* rei = NULL;
2691 gint curr_repo_index = gtk_combo_box_get_active (GTK_COMBO_BOX (rmi->cmb_repos));
2694 printf("%s()\n", __PRETTY_FUNCTION__);
2696 if (curr_repo_index < 0) {
2697 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
2701 rei = g_list_nth_data (rmi->repo_edits, curr_repo_index);
2704 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
2708 /* check that rei have repo data structure. If it haven't, it means that repository have just
2709 added, so report about this */
2711 GtkWidget *msg = hildon_note_new_information ( GTK_WINDOW (rmi->dialog),
2712 _("You cannot add layers to not saved repository,\nsorry. So, press ok in repository manager\n"
2713 "and open this dialog again."));
2715 gtk_dialog_run (GTK_DIALOG (msg));
2716 gtk_widget_destroy (msg);
2718 vprintf("%s(): return FALSE (3)\n", __PRETTY_FUNCTION__);
2722 header = g_malloc (strlen (t_header) + strlen (rei->name));
2723 sprintf (header, t_header, rei->name);
2725 printf ("Creating dialog with header: %s\n", header);
2727 rli.layer_edits = NULL;
2728 rli.dialog = gtk_dialog_new_with_buttons (header, GTK_WINDOW (rmi->dialog), GTK_DIALOG_MODAL,
2729 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2730 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
2732 rli.layers_store = gtk_list_store_new (1, G_TYPE_STRING);
2733 rli.layers_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (rli.layers_store));
2734 layers_rendeder = gtk_cell_renderer_text_new ();
2735 layers_column = gtk_tree_view_column_new_with_attributes ("Column", layers_rendeder, "text", 0, NULL);
2736 gtk_tree_view_append_column (GTK_TREE_VIEW (rli.layers_list), layers_column);
2738 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli.layers_list));
2740 frame = gtk_frame_new (NULL);
2741 gtk_container_add (GTK_CONTAINER (frame), rli.layers_list);
2742 gtk_widget_set_size_request (frame, -1, 100);
2744 /* beside layers list with have buttons on bottom */
2745 layers_vbox = gtk_vbox_new (FALSE, 4);
2746 gtk_box_pack_start (GTK_BOX (layers_vbox), frame, TRUE, TRUE, 0);
2747 gtk_box_pack_start (GTK_BOX (layers_vbox), buttons_hbox = gtk_hbox_new (FALSE, 4), FALSE, FALSE, 0);
2750 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_new = gtk_button_new_with_label (_("New")), FALSE, FALSE, 0);
2751 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_del = gtk_button_new_with_label (_("Del")), FALSE, FALSE, 0);
2752 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_up = gtk_button_new_with_label (_("Up")), FALSE, FALSE, 0);
2753 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_dn = gtk_button_new_with_label (_("Dn")), FALSE, FALSE, 0);
2756 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(repoman_layer_selected), &rli);
2757 g_signal_connect(G_OBJECT(btn_new), "clicked", G_CALLBACK(repoman_layers_new), &rli);
2758 g_signal_connect(G_OBJECT(btn_del), "clicked", G_CALLBACK(repoman_layers_del), &rli);
2759 g_signal_connect(G_OBJECT(btn_up), "clicked", G_CALLBACK(repoman_layers_up), &rli);
2760 g_signal_connect(G_OBJECT(btn_dn), "clicked", G_CALLBACK(repoman_layers_dn), &rli);
2762 /* notebook with layers' attributes */
2763 rli.notebook = gtk_notebook_new ();
2765 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rli.notebook), FALSE);
2766 gtk_notebook_set_show_border(GTK_NOTEBOOK(rli.notebook), FALSE);
2768 /* walk through all layers and add notebook pages */
2769 rd = rei->repo->layers;
2771 LayerEditInfo *lei = repoman_layers_add_layer (&rli, rd->name);
2773 gtk_entry_set_text (GTK_ENTRY (lei->txt_url), rd->url);
2774 gtk_entry_set_text (GTK_ENTRY (lei->txt_db), rd->db_filename);
2775 hildon_number_editor_set_value (HILDON_NUMBER_EDITOR (lei->num_autofetch), rd->layer_refresh_interval);
2776 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lei->chk_visible), rd->layer_enabled);
2781 /* pack all widgets together */
2782 hbox = gtk_hbox_new (FALSE, 4);
2784 gtk_box_pack_start (GTK_BOX (hbox), layers_vbox, TRUE, TRUE, 4);
2785 gtk_box_pack_start (GTK_BOX (hbox), rli.notebook, TRUE, TRUE, 4);
2787 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (rli.dialog)->vbox), hbox, FALSE, FALSE, 4);
2789 gtk_widget_show_all (rli.dialog);
2791 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (rli.dialog)))
2797 menu_layers_remove_repos ();
2799 /* iterate over notebook's pages and build layers */
2800 /* keep list in memory in case downloads use it (TODO: reference counting) */
2801 rdp = &rei->repo->layers;
2804 for (i = 0, curr = rli.layer_edits; curr; curr = curr->next, i++) {
2805 LayerEditInfo *lei = curr->data;
2807 rd = g_new0 (RepoData, 1);
2810 rd->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_name)));
2811 rd->url = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_url)));
2812 rd->db_filename = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_db)));
2813 rd->layer_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lei->chk_visible));
2814 rd->layer_refresh_interval = hildon_number_editor_get_value (HILDON_NUMBER_EDITOR (lei->num_autofetch));
2815 rd->layer_refresh_countdown = rd->layer_refresh_interval;
2816 rd->layer_level = i+1;
2818 rd->dl_zoom_steps = rei->repo->dl_zoom_steps;
2819 rd->view_zoom_steps = rei->repo->view_zoom_steps;
2820 rd->double_size = rei->repo->double_size;
2821 rd->nextable = rei->repo->nextable;
2822 rd->min_zoom = rei->repo->min_zoom;
2823 rd->max_zoom = rei->repo->max_zoom;
2829 menu_layers_add_repos ();
2830 repo_set_curr(_curr_repo);
2833 map_refresh_mark (TRUE);
2837 gtk_widget_destroy (rli.dialog);
2839 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2847 static RepoManInfo rmi;
2848 static GtkWidget *dialog = NULL;
2849 static GtkWidget *hbox = NULL;
2850 static GtkWidget *btn_rename = NULL;
2851 static GtkWidget *btn_delete = NULL;
2852 static GtkWidget *btn_new = NULL;
2853 static GtkWidget *btn_reset = NULL;
2854 static GtkWidget *btn_layers = NULL;
2855 gint i, curr_repo_index = 0;
2857 printf("%s()\n", __PRETTY_FUNCTION__);
2861 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
2862 _("Manage Repositories"),
2863 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2864 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2867 /* Enable the help button. */
2869 hildon_help_dialog_help_enable(
2871 ossohelp_dialog_help_enable(
2873 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
2876 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2877 btn_reset = gtk_button_new_with_label(_("Reset...")));
2878 g_signal_connect(G_OBJECT(btn_reset), "clicked",
2879 G_CALLBACK(repoman_reset), &rmi);
2881 /* Layers button. */
2882 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2883 btn_layers = gtk_button_new_with_label(_("Layers...")));
2884 g_signal_connect(G_OBJECT(btn_layers), "clicked",
2885 G_CALLBACK(repoman_layers), &rmi);
2887 /* Cancel button. */
2888 gtk_dialog_add_button(GTK_DIALOG(dialog),
2889 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2891 hbox = gtk_hbox_new(FALSE, 4);
2893 gtk_box_pack_start(GTK_BOX(hbox),
2894 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
2896 gtk_box_pack_start(GTK_BOX(hbox),
2897 gtk_vseparator_new(), FALSE, FALSE, 4);
2898 gtk_box_pack_start(GTK_BOX(hbox),
2899 btn_rename = gtk_button_new_with_label(_("Rename...")),
2901 gtk_box_pack_start(GTK_BOX(hbox),
2902 btn_delete = gtk_button_new_with_label(_("Delete...")),
2904 gtk_box_pack_start(GTK_BOX(hbox),
2905 btn_new = gtk_button_new_with_label(_("New...")),
2908 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2909 hbox, FALSE, FALSE, 4);
2911 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2912 gtk_hseparator_new(), TRUE, TRUE, 4);
2913 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2914 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
2916 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
2917 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
2919 rmi.repo_edits = NULL;
2921 /* Connect signals. */
2922 g_signal_connect(G_OBJECT(btn_rename), "clicked",
2923 G_CALLBACK(repoman_dialog_rename), &rmi);
2924 g_signal_connect(G_OBJECT(btn_delete), "clicked",
2925 G_CALLBACK(repoman_dialog_delete), &rmi);
2926 g_signal_connect(G_OBJECT(btn_new), "clicked",
2927 G_CALLBACK(repoman_dialog_new), &rmi);
2928 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
2929 G_CALLBACK(repoman_dialog_select), &rmi);
2932 /* Populate combo box and pages in notebook. */
2933 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
2935 RepoData *rd = (RepoData*)curr->data;
2936 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
2938 /* store this to be able to walk through layers attached to repo */
2941 /* Initialize fields with data from the RepoData object. */
2942 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2943 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
2945 hildon_controlbar_set_value(
2946 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2948 hildon_controlbar_set_value(
2949 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2950 rd->view_zoom_steps);
2951 gtk_toggle_button_set_active(
2952 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2954 gtk_toggle_button_set_active(
2955 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2957 hildon_number_editor_set_value(
2958 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2960 hildon_number_editor_set_value(
2961 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2963 if(rd == _curr_repo)
2964 curr_repo_index = i;
2967 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
2968 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
2970 gtk_widget_show_all(dialog);
2972 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2974 /* Iterate through repos and verify each. */
2975 gboolean verified = TRUE;
2978 gchar *old_curr_repo_name = _curr_repo->name;
2980 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2982 /* Check the ranges for the min and max zoom levels. */
2983 RepoEditInfo *rei = curr->data;
2984 if(hildon_number_editor_get_value(
2985 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
2986 < hildon_number_editor_get_value(
2987 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
2995 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
2997 _("Minimum Downloadable Zoom must be less than "
2998 "Maximum Downloadable Zoom."));
3002 /* We're good to replace. Remove old _repo_list menu items. */
3003 menu_maps_remove_repos();
3004 /* But keep the repo list in memory, in case downloads are using it. */
3007 /* Write new _repo_list. */
3008 curr_repo_index = gtk_combo_box_get_active(
3009 GTK_COMBO_BOX(rmi.cmb_repos));
3011 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
3013 RepoEditInfo *rei = curr->data;
3014 RepoData *rd = g_new0(RepoData, 1);
3015 RepoData *rd0, **rd1;
3016 rd->name = g_strdup(rei->name);
3017 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
3018 rd->db_filename = gnome_vfs_expand_initial_tilde(
3019 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
3020 rd->dl_zoom_steps = hildon_controlbar_get_value(
3021 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
3022 rd->view_zoom_steps = hildon_controlbar_get_value(
3023 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
3024 rd->double_size = gtk_toggle_button_get_active(
3025 GTK_TOGGLE_BUTTON(rei->chk_double_size));
3026 rd->nextable = gtk_toggle_button_get_active(
3027 GTK_TOGGLE_BUTTON(rei->chk_nextable));
3028 rd->min_zoom = hildon_number_editor_get_value(
3029 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
3030 rd->max_zoom = hildon_number_editor_get_value(
3031 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
3035 rd0 = rei->repo->layers;
3039 *rd1 = g_new0 (RepoData, 1);
3040 (*rd1)->name = rd0->name;
3041 (*rd1)->url = rd0->url;
3042 (*rd1)->db_filename = rd0->db_filename;
3043 (*rd1)->layer_enabled = rd0->layer_enabled;
3044 (*rd1)->layer_refresh_interval = rd0->layer_refresh_interval;
3045 (*rd1)->layer_refresh_countdown = rd0->layer_refresh_countdown;
3046 (*rd1)->layer_level = rd0->layer_level;
3048 (*rd1)->dl_zoom_steps = rd0->dl_zoom_steps;
3049 (*rd1)->view_zoom_steps = rd0->view_zoom_steps;
3050 (*rd1)->double_size = rd0->double_size;
3051 (*rd1)->nextable = rd0->nextable;
3052 (*rd1)->min_zoom = rd0->min_zoom;
3053 (*rd1)->max_zoom = rd0->max_zoom;
3055 set_repo_type (*rd1);
3058 rd1 = &(*rd1)->layers;
3065 rd->layer_level = 0;
3068 _repo_list = g_list_append(_repo_list, rd);
3070 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
3072 else if(i == curr_repo_index)
3076 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
3077 menu_maps_add_repos();
3083 gtk_widget_hide(dialog);
3085 /* Clear out the notebook entries. */
3086 while(rmi.repo_edits)
3087 repoman_delete(&rmi, 0);
3089 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
3090 map_refresh_mark (TRUE);
3092 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3097 mapman_by_area(gdouble start_lat, gdouble start_lon,
3098 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
3099 MapUpdateType update_type,
3100 gint download_batch_id)
3102 gint start_unitx, start_unity, end_unitx, end_unity;
3107 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
3110 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
3111 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
3113 /* Swap if they specified flipped lats or lons. */
3114 if(start_unitx > end_unitx)
3116 gint swap = start_unitx;
3117 start_unitx = end_unitx;
3120 if(start_unity > end_unity)
3122 gint swap = start_unity;
3123 start_unity = end_unity;
3127 /* First, get the number of maps to download. */
3128 for(z = 0; z <= MAX_ZOOM; ++z)
3130 if(gtk_toggle_button_get_active(
3131 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3133 gint start_tilex, start_tiley, end_tilex, end_tiley;
3134 start_tilex = unit2ztile(start_unitx, z);
3135 start_tiley = unit2ztile(start_unity, z);
3136 end_tilex = unit2ztile(end_unitx, z);
3137 end_tiley = unit2ztile(end_unity, z);
3138 num_maps += (end_tilex - start_tilex + 1)
3139 * (end_tiley - start_tiley + 1);
3143 if(update_type == MAP_UPDATE_DELETE)
3145 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
3146 num_maps, _("maps "));
3150 snprintf(buffer, sizeof(buffer),
3151 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
3152 num_maps, _("maps"), _("up to about"),
3153 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
3155 confirm = hildon_note_new_confirmation(
3156 GTK_WINDOW(mapman_info->dialog), buffer);
3158 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
3160 gtk_widget_destroy(confirm);
3161 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
3165 g_mutex_lock(_mut_priority_mutex);
3166 for(z = 0; z <= MAX_ZOOM; ++z)
3168 if(gtk_toggle_button_get_active(
3169 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3171 gint start_tilex, start_tiley, end_tilex, end_tiley;
3173 start_tilex = unit2ztile(start_unitx, z);
3174 start_tiley = unit2ztile(start_unity, z);
3175 end_tilex = unit2ztile(end_unitx, z);
3176 end_tiley = unit2ztile(end_unity, z);
3177 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
3179 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
3181 /* Make sure this tile is even possible. */
3182 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
3183 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
3185 RepoData* rd = _curr_repo;
3188 if (rd == _curr_repo || (rd->layer_enabled && rd->db))
3189 mapdb_initiate_update(rd, z, tilex, tiley,
3190 update_type, download_batch_id,
3191 (abs(tilex - unit2tile(_next_center.unitx))
3192 + abs(tiley - unit2tile(_next_center.unity))),
3201 g_mutex_unlock(_mut_priority_mutex);
3203 gtk_widget_destroy(confirm);
3204 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3209 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
3210 gint download_batch_id)
3213 gint prev_tilex, prev_tiley, num_maps = 0, z;
3216 gint radius = hildon_number_editor_get_value(
3217 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
3218 printf("%s()\n", __PRETTY_FUNCTION__);
3220 /* First, get the number of maps to download. */
3221 for(z = 0; z <= MAX_ZOOM; ++z)
3223 if(gtk_toggle_button_get_active(
3224 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3228 for(curr = _route.head - 1; curr++ != _route.tail; )
3232 gint tilex = unit2ztile(curr->unitx, z);
3233 gint tiley = unit2ztile(curr->unity, z);
3234 if(tilex != prev_tilex || tiley != prev_tiley)
3237 num_maps += (abs((gint)tilex - prev_tilex) + 1)
3238 * (abs((gint)tiley - prev_tiley) + 1) - 1;
3246 num_maps *= 0.625 * pow(radius + 1, 1.85);
3248 if(update_type == MAP_UPDATE_DELETE)
3250 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
3251 _("Confirm DELETION of"), _("about"),
3252 num_maps, _("maps "));
3256 snprintf(buffer, sizeof(buffer),
3257 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
3259 num_maps, _("maps"), _("up to about"),
3260 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
3262 confirm = hildon_note_new_confirmation(
3263 GTK_WINDOW(mapman_info->dialog), buffer);
3265 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
3267 gtk_widget_destroy(confirm);
3268 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
3272 /* Now, do the actual download. */
3273 g_mutex_lock(_mut_priority_mutex);
3274 for(z = 0; z <= MAX_ZOOM; ++z)
3276 if(gtk_toggle_button_get_active(
3277 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3281 for(curr = _route.head - 1; curr++ != _route.tail; )
3285 gint tilex = unit2ztile(curr->unitx, z);
3286 gint tiley = unit2ztile(curr->unity, z);
3287 if(tilex != prev_tilex || tiley != prev_tiley)
3289 gint minx, miny, maxx, maxy, x, y;
3292 minx = MIN(tilex, prev_tilex) - radius;
3293 miny = MIN(tiley, prev_tiley) - radius;
3294 maxx = MAX(tilex, prev_tilex) + radius;
3295 maxy = MAX(tiley, prev_tiley) + radius;
3299 minx = tilex - radius;
3300 miny = tiley - radius;
3301 maxx = tilex + radius;
3302 maxy = tiley + radius;
3304 for(x = minx; x <= maxx; x++)
3306 for(y = miny; y <= maxy; y++)
3308 /* Make sure this tile is even possible. */
3310 < unit2ztile(WORLD_SIZE_UNITS, z)
3312 < unit2ztile(WORLD_SIZE_UNITS, z))
3314 mapdb_initiate_update(_curr_repo, z, x, y,
3315 update_type, download_batch_id,
3316 (abs(tilex - unit2tile(
3317 _next_center.unitx))
3318 + abs(tiley - unit2tile(
3319 _next_center.unity))),
3331 g_mutex_unlock(_mut_priority_mutex);
3332 _route_dl_radius = radius;
3333 gtk_widget_destroy(confirm);
3334 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3339 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
3342 printf("%s()\n", __PRETTY_FUNCTION__);
3343 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
3344 /* This is the second page (the "Zoom" page) - clear the checks. */
3345 for(z = 0; z <= MAX_ZOOM; ++z)
3346 gtk_toggle_button_set_active(
3347 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
3350 /* This is the first page (the "Area" page) - clear the text fields. */
3351 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
3352 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
3353 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
3354 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
3356 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3359 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
3361 printf("%s()\n", __PRETTY_FUNCTION__);
3362 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
3363 gtk_toggle_button_get_active(
3364 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
3366 if(gtk_toggle_button_get_active(
3367 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
3368 gtk_widget_show(mapman_info->tbl_area);
3369 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
3370 gtk_widget_hide(mapman_info->tbl_area);
3372 gtk_widget_set_sensitive(mapman_info->num_route_radius,
3373 gtk_toggle_button_get_active(
3374 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
3375 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3381 static GtkWidget *dialog = NULL;
3382 static GtkWidget *vbox = NULL;
3383 static GtkWidget *hbox = NULL;
3384 static GtkWidget *table = NULL;
3385 static GtkWidget *label = NULL;
3386 static GtkWidget *button = NULL;
3387 static GtkWidget *lbl_gps_lat = NULL;
3388 static GtkWidget *lbl_gps_lon = NULL;
3389 static GtkWidget *lbl_center_lat = NULL;
3390 static GtkWidget *lbl_center_lon = NULL;
3391 static MapmanInfo mapman_info;
3392 static gint last_deg_format = 0;
3397 gint prev_degformat = _degformat;
3398 gint fallback_deg_format = _degformat;
3399 gdouble top_left_lat, top_left_lon, bottom_right_lat, bottom_right_lon;
3402 printf("%s()\n", __PRETTY_FUNCTION__);
3406 popup_error(_window, "To manage maps, you must set a valid repository "
3407 "database filename in the \"Manage Repositories\" dialog.");
3408 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3412 // - If the coord system has changed then we need to update certain values
3414 /* Initialize to the bounds of the screen. */
3416 _center.unitx - pixel2unit(MAX(_view_width_pixels,
3417 _view_height_pixels) / 2),
3418 _center.unity - pixel2unit(MAX(_view_width_pixels,
3419 _view_height_pixels) / 2), top_left_lat, top_left_lon);
3421 BOUND(top_left_lat, -90.f, 90.f);
3422 BOUND(top_left_lon, -180.f, 180.f);
3426 _center.unitx + pixel2unit(MAX(_view_width_pixels,
3427 _view_height_pixels) / 2),
3428 _center.unity + pixel2unit(MAX(_view_width_pixels,
3429 _view_height_pixels) / 2), bottom_right_lat, bottom_right_lon);
3430 BOUND(bottom_right_lat, -90.f, 90.f);
3431 BOUND(bottom_right_lon, -180.f, 180.f);
3436 if(!coord_system_check_lat_lon (top_left_lat, top_left_lon, &fallback_deg_format))
3438 _degformat = fallback_deg_format;
3442 // top left is valid, also check bottom right
3443 if(!coord_system_check_lat_lon (bottom_right_lat, bottom_right_lon, &fallback_deg_format))
3445 _degformat = fallback_deg_format;
3450 if(_degformat != last_deg_format)
3452 last_deg_format = _degformat;
3454 if(dialog != NULL) gtk_widget_destroy(dialog);
3460 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
3462 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
3463 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
3466 /* Enable the help button. */
3468 hildon_help_dialog_help_enable(
3470 ossohelp_dialog_help_enable(
3472 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
3475 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
3476 button = gtk_button_new_with_label(_("Clear")));
3477 g_signal_connect(G_OBJECT(button), "clicked",
3478 G_CALLBACK(mapman_clear), &mapman_info);
3480 /* Cancel button. */
3481 gtk_dialog_add_button(GTK_DIALOG(dialog),
3482 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
3484 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
3485 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
3488 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3489 vbox = gtk_vbox_new(FALSE, 2),
3490 label = gtk_label_new(_("Setup")));
3491 gtk_notebook_set_tab_label_packing(
3492 GTK_NOTEBOOK(mapman_info.notebook), vbox,
3493 FALSE, FALSE, GTK_PACK_START);
3495 gtk_box_pack_start(GTK_BOX(vbox),
3496 hbox = gtk_hbox_new(FALSE, 4),
3498 gtk_box_pack_start(GTK_BOX(hbox),
3499 mapman_info.rad_download = gtk_radio_button_new_with_label(
3500 NULL,_("Download Maps")),
3502 gtk_box_pack_start(GTK_BOX(hbox),
3503 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
3505 gtk_container_add(GTK_CONTAINER(label),
3506 mapman_info.chk_overwrite
3507 = gtk_check_button_new_with_label(_("Overwrite"))),
3509 gtk_box_pack_start(GTK_BOX(vbox),
3510 mapman_info.rad_delete
3511 = gtk_radio_button_new_with_label_from_widget(
3512 GTK_RADIO_BUTTON(mapman_info.rad_download),
3516 gtk_box_pack_start(GTK_BOX(vbox),
3517 gtk_hseparator_new(),
3520 gtk_box_pack_start(GTK_BOX(vbox),
3521 mapman_info.rad_by_area
3522 = gtk_radio_button_new_with_label(NULL,
3523 _("By Area (see tab)")),
3525 gtk_box_pack_start(GTK_BOX(vbox),
3526 hbox = gtk_hbox_new(FALSE, 4),
3528 gtk_box_pack_start(GTK_BOX(hbox),
3529 mapman_info.rad_by_route
3530 = gtk_radio_button_new_with_label_from_widget(
3531 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
3532 _("Along Route - Radius (tiles):")),
3534 gtk_box_pack_start(GTK_BOX(hbox),
3535 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
3537 hildon_number_editor_set_value(
3538 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
3543 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3544 table = gtk_table_new(5, 5, FALSE),
3545 label = gtk_label_new(_("Zoom")));
3546 gtk_notebook_set_tab_label_packing(
3547 GTK_NOTEBOOK(mapman_info.notebook), table,
3548 FALSE, FALSE, GTK_PACK_START);
3549 gtk_table_attach(GTK_TABLE(table),
3550 label = gtk_label_new(
3551 _("Zoom Levels to Download: (0 = most detail)")),
3552 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
3553 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
3554 snprintf(buffer, sizeof(buffer), "%d", 0);
3555 gtk_table_attach(GTK_TABLE(table),
3556 mapman_info.chk_zoom_levels[0]
3557 = gtk_check_button_new_with_label(buffer),
3558 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
3559 for(z = 0; z < MAX_ZOOM; ++z)
3561 snprintf(buffer, sizeof(buffer), "%d", z + 1);
3562 gtk_table_attach(GTK_TABLE(table),
3563 mapman_info.chk_zoom_levels[z + 1]
3564 = gtk_check_button_new_with_label(buffer),
3565 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
3570 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3571 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
3572 label = gtk_label_new(_("Area")));
3574 /* Label Columns. */
3575 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3576 label = gtk_label_new(DEG_FORMAT_ENUM_TEXT[_degformat].long_field_1),
3577 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
3578 gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
3580 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3582 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3583 label = gtk_label_new(DEG_FORMAT_ENUM_TEXT[_degformat].long_field_2),
3584 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
3585 gtk_misc_set_alignment(GTK_MISC(label), 0.5f, 0.5f);
3589 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3590 label = gtk_label_new(_("GPS Location")),
3591 0, 1, 1, 2, GTK_FILL, 0, 4, 0);
3592 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3593 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3594 lbl_gps_lat = gtk_label_new(""),
3595 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
3596 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
3597 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
3599 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3601 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3602 lbl_gps_lon = gtk_label_new(""),
3603 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
3604 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
3605 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
3609 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3610 label = gtk_label_new(_("View Center")),
3611 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
3612 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3613 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3614 lbl_center_lat = gtk_label_new(""),
3615 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
3616 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
3617 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
3620 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3622 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3623 lbl_center_lon = gtk_label_new(""),
3624 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
3625 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
3626 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
3629 /* default values for Top Left and Bottom Right are defined by the
3630 * rectangle of the current and the previous Center */
3633 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3634 label = gtk_label_new(_("Top-Left")),
3635 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
3636 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3637 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3638 mapman_info.txt_topleft_lat = gtk_entry_new(),
3639 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
3640 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
3641 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
3642 #ifdef MAEMO_CHANGES
3643 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
3645 "hildon-input-mode",
3646 HILDON_GTK_INPUT_MODE_FULL, NULL);
3648 HILDON_INPUT_MODE_HINT,
3649 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3650 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
3656 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3658 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3659 mapman_info.txt_topleft_lon = gtk_entry_new(),
3660 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
3661 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
3662 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
3663 #ifdef MAEMO_CHANGES
3664 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
3666 "hildon-input-mode",
3667 HILDON_GTK_INPUT_MODE_FULL, NULL);
3669 HILDON_INPUT_MODE_HINT,
3670 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3671 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
3680 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3681 label = gtk_label_new(_("Bottom-Right")),
3682 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
3683 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3684 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3685 mapman_info.txt_botright_lat = gtk_entry_new(),
3686 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
3687 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
3688 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
3689 #ifdef MAEMO_CHANGES
3690 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
3692 "hildon-input-mode",
3693 HILDON_GTK_INPUT_MODE_FULL, NULL);
3695 HILDON_INPUT_MODE_HINT,
3696 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3697 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
3703 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3705 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3706 mapman_info.txt_botright_lon = gtk_entry_new(),
3707 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
3708 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lon), 12);
3709 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
3710 #ifdef MAEMO_CHANGES
3711 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
3713 "hildon-input-mode",
3714 HILDON_GTK_INPUT_MODE_FULL, NULL);
3716 HILDON_INPUT_MODE_HINT,
3717 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3718 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
3726 /* Default action is to download by area. */
3727 gtk_toggle_button_set_active(
3728 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
3730 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
3731 G_CALLBACK(mapman_update_state), &mapman_info);
3732 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
3733 G_CALLBACK(mapman_update_state), &mapman_info);
3734 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
3735 G_CALLBACK(mapman_update_state), &mapman_info);
3736 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
3737 G_CALLBACK(mapman_update_state), &mapman_info);
3740 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
3741 * output (and parsed) as locale-dependent. */
3743 gtk_widget_set_sensitive(mapman_info.rad_by_route,
3744 _route.head != _route.tail);
3749 format_lat_lon(_gps.lat, _gps.lon, buffer1, buffer2);
3750 //lat_format(_gps.lat, buffer);
3751 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer1);
3752 //lon_format(_gps.lon, buffer);
3753 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3754 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer2);
3756 unit2latlon(_center.unitx, _center.unity, lat, lon);
3758 format_lat_lon(lat, lon, buffer1, buffer2);
3759 //lat_format(lat, buffer);
3760 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer1);
3761 //lon_format(lon, buffer);
3762 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3763 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer2);
3765 format_lat_lon(top_left_lat, top_left_lon, buffer1, buffer2);
3767 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer1);
3769 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3770 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer2);
3772 format_lat_lon(bottom_right_lat, bottom_right_lon, buffer1, buffer2);
3773 //lat_format(lat, buffer);
3774 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer1);
3775 //lon_format(lon, buffer);
3776 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
3777 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer2);
3779 /* Initialize zoom levels. */
3782 for(i = 0; i <= MAX_ZOOM; i++)
3784 gtk_toggle_button_set_active(
3785 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
3788 gtk_toggle_button_set_active(
3789 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
3790 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
3792 gtk_widget_show_all(dialog);
3794 mapman_update_state(NULL, &mapman_info);
3796 if(_curr_repo->type != REPOTYPE_NONE)
3798 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
3802 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
3804 _("NOTE: You must set a Map URI in the current repository in "
3805 "order to download maps."));
3808 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
3810 MapUpdateType update_type;
3811 static gint8 download_batch_id = INT8_MIN;
3813 if(gtk_toggle_button_get_active(
3814 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
3815 update_type = MAP_UPDATE_DELETE;
3816 else if(gtk_toggle_button_get_active(
3817 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
3818 update_type = MAP_UPDATE_OVERWRITE;
3820 update_type = MAP_UPDATE_ADD;
3822 ++download_batch_id;
3823 if(gtk_toggle_button_get_active(
3824 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
3826 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
3831 const gchar *text_lon, *text_lat;
3832 //gchar *error_check;
3833 gdouble start_lat, start_lon, end_lat, end_lon;
3835 text_lat = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
3836 text_lon = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
3838 if(!parse_coords(text_lat, text_lon, &start_lat, &start_lon))
3840 popup_error(dialog, _("Invalid Top-Left coordinate specified"));
3844 text_lat = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
3845 text_lon = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
3847 if(!parse_coords(text_lat, text_lon, &end_lat, &end_lon))
3849 popup_error(dialog, _("Invalid Bottom-Right coordinate specified"));
3855 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
3856 &mapman_info, update_type, download_batch_id))
3861 gtk_widget_hide(dialog);
3863 _degformat = prev_degformat;
3865 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3870 /* changes visibility of current repo's layers to it's previous state */
3871 void maps_toggle_visible_layers ()
3873 RepoData *rd = _curr_repo;
3874 gboolean changed = FALSE;
3876 printf("%s()\n", __PRETTY_FUNCTION__);
3879 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3886 if (rd->layer_enabled) {
3888 rd->layer_was_enabled = rd->layer_enabled;
3889 rd->layer_enabled = FALSE;
3892 rd->layer_enabled = rd->layer_was_enabled;
3893 if (rd->layer_was_enabled)
3902 menu_layers_remove_repos ();
3903 menu_layers_add_repos ();
3905 map_refresh_mark (TRUE);
3908 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3913 /* this routine fired by timer every minute and decrements refetch counter of every active layer of
3914 current repository. If one of layer is expired, it forces map redraw. Redraw routine checks every
3915 layer's tile download timestamp and desides performs refetch if needed */
3917 map_layer_refresh_cb (gpointer data)
3919 RepoData* rd = _curr_repo;
3920 gboolean refresh = FALSE;
3921 printf("%s()\n", __PRETTY_FUNCTION__);
3927 if (rd->layer_enabled && rd->layer_refresh_interval) {
3928 rd->layer_refresh_countdown--;
3929 if (rd->layer_refresh_countdown <= 0) {
3930 rd->layer_refresh_countdown = rd->layer_refresh_interval;
3940 map_refresh_mark (TRUE);
3942 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3949 Returns amount of seconds since tile downloaded or 0 if tile
3950 have no such information.
3952 gint get_tile_age (GdkPixbuf* pixbuf)
3957 ts = gdk_pixbuf_get_option (pixbuf, layer_timestamp_key);
3962 if (sscanf (ts, "%u", &val))
3963 return time (NULL) - val;