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(size_t cache_size)
549 g_mutex_lock(_mapdb_mutex);
550 if(_map_cache.entries == NULL)
551 _map_cache.entries = g_hash_table_new_full(map_cache_key_hash,
552 map_cache_key_equal, NULL, (GDestroyNotify)map_cache_entry_free);
553 _map_cache.cache_size = cache_size;
554 if(_map_cache.p > cache_size)
555 _map_cache.p = cache_size;
557 g_mutex_unlock(_mapdb_mutex);
561 map_cache_resize(size_t cache_size)
564 g_mutex_lock(_mapdb_mutex);
565 _map_cache.cache_size = cache_size;
566 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
567 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
568 g_mutex_unlock(_mapdb_mutex);
573 map_cache_destroy(void)
575 g_mutex_lock(_mapdb_mutex);
576 if(_map_cache.entries != NULL)
578 g_hash_table_destroy(_map_cache.entries);
579 _map_cache.entries = NULL;
580 printf("thits: %u (%0.2f%%) bhits: %u (%0.2f%%) "
581 "misses: %u (%0.2f%%)\n",
582 _map_cache.thits, 100*_map_cache.thits/(double)(
583 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
584 _map_cache.bhits, 100*_map_cache.bhits/(double)(
585 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
586 _map_cache.misses, 100*_map_cache.misses/(double)(
587 _map_cache.thits+_map_cache.bhits+_map_cache.misses));
589 g_mutex_unlock(_mapdb_mutex);
594 map_cache_clean (void)
596 g_mutex_lock(_mapdb_mutex);
597 if(_map_cache.entries != NULL)
598 g_hash_table_remove_all (_map_cache.entries);
599 g_mutex_unlock(_mapdb_mutex);
604 mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley)
607 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
608 repo->name, zoom, tilex, tiley);
610 g_mutex_lock(_mapdb_mutex);
614 /* There is no cache. Return FALSE. */
615 g_mutex_unlock(_mapdb_mutex);
616 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
620 /* Search the cache first. */
623 MapCacheEntry *entry;
628 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
632 ret = entry->data != NULL;
633 g_mutex_unlock(_mapdb_mutex);
639 /* Attempt to retrieve map from database. */
640 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom)
641 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex)
642 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley)
643 && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists)
644 && sqlite3_column_int(repo->stmt_map_exists, 0) > 0)
652 sqlite3_reset(repo->stmt_map_exists);
661 d.dptr = (gchar*)&key;
662 d.dsize = sizeof(key);
663 exists = gdbm_exists(repo->db, d);
667 g_mutex_unlock(_mapdb_mutex);
669 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists);
674 mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
677 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
678 repo->name, zoom, tilex, tiley);
679 g_mutex_lock(_mapdb_mutex);
680 pixbuf = map_cache_get(repo, zoom, tilex, tiley);
681 g_mutex_unlock(_mapdb_mutex);
682 vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf);
688 mapdb_checkdec(RepoData *repo, gint zoom, gint tilex, gint tiley)
690 gboolean success = TRUE;
691 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
692 repo->name, zoom, tilex, tiley);
694 /* First, we have to check if the old map was a dup. */
695 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
696 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
697 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
698 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)
699 && sqlite3_column_bytes(repo->stmt_map_select, 0)
700 <= MAX_PIXBUF_DUP_SIZE)
702 /* Old map was indeed a dup. Decrement the reference count. */
703 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
704 if(SQLITE_OK != sqlite3_bind_int(
705 repo->stmt_dup_decrem, 1, hash)
706 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_decrem)
707 || SQLITE_OK != sqlite3_bind_int(
708 repo->stmt_dup_delete, 1, hash)
709 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_delete))
712 printf("Error in stmt_dup_decrem: %s\n",
713 sqlite3_errmsg(repo->db));
715 sqlite3_reset(repo->stmt_dup_delete);
716 sqlite3_reset(repo->stmt_dup_decrem);
718 sqlite3_reset(repo->stmt_map_select);
720 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
726 mapdb_update(gboolean exists, RepoData *repo,
727 gint zoom, gint tilex, gint tiley, void *bytes, gint size)
734 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
735 repo->name, zoom, tilex, tiley);
737 g_mutex_lock(_mapdb_mutex);
738 map_cache_update(repo, zoom, tilex, tiley, bytes, size);
742 /* There is no cache. Return FALSE. */
743 g_mutex_unlock(_mapdb_mutex);
744 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
749 /* At least try to open a transaction. */
750 sqlite3_step(repo->stmt_trans_begin);
751 sqlite3_reset(repo->stmt_trans_begin);
753 /* Pixbufs of size MAX_PIXBUF_DUP_SIZE or less are special. They are
754 * probably PNGs of a single color (like blue for water or beige for empty
755 * land). To reduce redundancy in the database, we will store them in a
756 * separate table and, in the maps table, only refer to them. */
757 if(size <= MAX_PIXBUF_DUP_SIZE)
759 /* Duplicate pixbuf. */
762 /* First, check if we need to remove a count from the dups table.*/
763 mapdb_checkdec(repo, zoom, tilex, tiley);
767 /* Compute hash of the bytes. */
768 gchar *cur = bytes, *end = bytes + size;
771 hash = (hash << 5) - hash + *(++cur);
773 /* Check if dup already exists. */
774 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_exists, 1, hash)
775 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_exists)
776 && sqlite3_column_int(repo->stmt_dup_exists, 0) > 0)
778 /* Dup already exists - increment existing entry. */
779 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_increm,1, hash)
780 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_increm))
783 printf("Error in stmt_dup_increm: %s\n",
784 sqlite3_errmsg(repo->db));
786 sqlite3_reset(repo->stmt_dup_increm);
790 /* Dup doesn't exist - add new entry. */
791 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_insert,1, hash)
792 || SQLITE_OK != sqlite3_bind_blob(repo->stmt_dup_insert,
793 2, bytes, size, NULL)
794 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_insert))
797 printf("Error in stmt_dup_insert: %s\n",
798 sqlite3_errmsg(repo->db));
800 sqlite3_reset(repo->stmt_dup_insert);
802 sqlite3_reset(repo->stmt_dup_exists);
804 /* Now, if successful so far, we fall through the end of this if
805 * statement and insert the hash as the blob. Setting bytes to NULL
806 * is the signal to do this. */
812 stmt = exists ? repo->stmt_map_update : repo->stmt_map_insert;
814 /* Attempt to insert map from database. */
815 if(SQLITE_OK != (bytes ? sqlite3_bind_blob(stmt, 1, bytes, size, NULL)
816 : sqlite3_bind_int(stmt, 1, hash))
817 || SQLITE_OK != sqlite3_bind_int(stmt, 2, zoom)
818 || SQLITE_OK != sqlite3_bind_int(stmt, 3, tilex)
819 || SQLITE_OK != sqlite3_bind_int(stmt, 4, tiley)
820 || SQLITE_DONE != sqlite3_step(stmt))
823 printf("Error in mapdb_update: %s\n", sqlite3_errmsg(repo->db));
830 sqlite3_step(repo->stmt_trans_commit);
831 sqlite3_reset(repo->stmt_trans_commit);
835 sqlite3_step(repo->stmt_trans_rollback);
836 sqlite3_reset(repo->stmt_trans_rollback);
847 dkey.dptr = (gchar*)&key;
848 dkey.dsize = sizeof(key);
851 success = !gdbm_store(repo->db, dkey, dcon, GDBM_REPLACE);
854 g_mutex_unlock(_mapdb_mutex);
856 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
861 mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley)
863 gint success = FALSE;
864 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
865 repo->name, zoom, tilex, tiley);
867 g_mutex_lock(_mapdb_mutex);
868 map_cache_remove(repo, zoom, tilex, tiley);
872 /* There is no cache. Return FALSE. */
873 g_mutex_unlock(_mapdb_mutex);
874 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
879 /* At least try to open a transaction. */
880 sqlite3_step(repo->stmt_trans_begin);
881 sqlite3_reset(repo->stmt_trans_begin);
883 /* First, check if we need to remove a count from the dups table. */
884 /* Then, attempt to delete map from database. */
885 if(!mapdb_checkdec(repo, zoom, tilex, tiley)
886 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 1, zoom)
887 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 2, tilex)
888 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 3, tiley)
889 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
892 printf("Error in stmt_map_delete: %s\n",
893 sqlite3_errmsg(repo->db));
895 sqlite3_reset(repo->stmt_map_delete);
899 sqlite3_step(repo->stmt_trans_commit);
900 sqlite3_reset(repo->stmt_trans_commit);
904 sqlite3_step(repo->stmt_trans_rollback);
905 sqlite3_reset(repo->stmt_trans_rollback);
915 d.dptr = (gchar*)&key;
916 d.dsize = sizeof(key);
917 success = !gdbm_delete(repo->db, d);
920 g_mutex_unlock(_mapdb_mutex);
922 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
927 set_repo_type(RepoData *repo)
929 printf("%s(%s)\n", __PRETTY_FUNCTION__, repo->url);
931 if(repo->url && *repo->url)
933 gchar *url = g_utf8_strdown(repo->url, -1);
935 /* Determine type of repository. */
936 if(strstr(url, "service=wms"))
937 repo->type = REPOTYPE_WMS;
938 else if(strstr(url, "%s"))
939 repo->type = REPOTYPE_QUAD_QRST;
940 else if(strstr(url, "%0d"))
941 repo->type = REPOTYPE_XYZ_INV;
942 else if(strstr(url, "%-d"))
943 repo->type = REPOTYPE_XYZ_SIGNED;
944 else if(strstr(url, "%0s"))
945 repo->type = REPOTYPE_QUAD_ZERO;
947 repo->type = REPOTYPE_XYZ;
952 repo->type = REPOTYPE_NONE;
954 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
957 /* Returns the directory containing the given database filename, or NULL
958 * if the database file could not be created. */
960 repo_make_db(RepoData *rd)
962 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
966 db_dirname = g_path_get_dirname(rd->db_filename);
968 /* Check if db_filename is a directory and ask to upgrade. */
969 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
971 gchar buffer[BUFFER_SIZE];
972 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
973 g_free(rd->db_filename);
974 rd->db_filename = new_name;
976 snprintf(buffer, sizeof(buffer), "%s",
977 _("The current repository is in a legacy format and will "
978 "be converted. You should delete your old maps if you "
979 "no longer plan to use them."));
980 popup_error(_window, buffer);
983 if(g_mkdir_with_parents(db_dirname, 0755))
990 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
992 fd = g_creat(rd->db_filename, 0644);
1001 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
1002 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
1003 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
1007 repo_set_curr(RepoData *rd)
1011 printf("%s()\n", __PRETTY_FUNCTION__);
1012 if(!rd->db_filename || !*rd->db_filename
1013 || repo_make_db(rd))
1015 repo_p = _curr_repo;
1021 g_mutex_lock(_mapdb_mutex);
1023 sqlite3_close(repo_p->db);
1026 gdbm_close(repo_p->db);
1029 g_mutex_unlock(_mapdb_mutex);
1031 repo_p = repo_p->layers;
1034 /* Set the current repository! */
1037 /* Set up the database. */
1038 if(_curr_repo->db_filename && *_curr_repo->db_filename)
1042 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
1044 /* Open worked. Now create tables, failing if they already exist.*/
1045 || (sqlite3_exec(_curr_repo->db,
1046 "create table maps ("
1051 "primary key (zoom, tilex, tiley))"
1053 "create table dups ("
1054 "hash integer primary key, "
1057 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
1058 /* Prepare select map statement. */
1059 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1060 "select pixbuf from maps "
1061 "where zoom = ? and tilex = ? and tiley = ?",
1062 -1, &_curr_repo->stmt_map_select, NULL)
1063 /* Prepare exists map statement. */
1064 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1065 "select count(*) from maps "
1066 "where zoom = ? and tilex = ? and tiley = ?",
1067 -1, &_curr_repo->stmt_map_exists, NULL)
1068 /* Prepare insert map statement. */
1069 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1070 "insert into maps (pixbuf, zoom, tilex, tiley)"
1071 " values (?, ?, ?, ?)",
1072 -1, &_curr_repo->stmt_map_insert, NULL)
1073 /* Prepare update map statement. */
1074 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1075 "update maps set pixbuf = ? "
1076 "where zoom = ? and tilex = ? and tiley = ?",
1077 -1, &_curr_repo->stmt_map_update, NULL)
1078 /* Prepare delete map statement. */
1079 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1081 "where zoom = ? and tilex = ? and tiley = ?",
1082 -1, &_curr_repo->stmt_map_delete, NULL)
1084 /* Prepare select-by-map dup statement. */
1085 /* Prepare select-by-hash dup statement. */
1086 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1087 "select pixbuf from dups "
1089 -1, &_curr_repo->stmt_dup_select, NULL)
1090 /* Prepare exists map statement. */
1091 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1092 "select count(*) from dups "
1094 -1, &_curr_repo->stmt_dup_exists, NULL)
1095 /* Prepare insert dup statement. */
1096 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1097 "insert into dups (hash, pixbuf, uses) "
1099 -1, &_curr_repo->stmt_dup_insert, NULL)
1100 /* Prepare increment dup statement. */
1101 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1103 "set uses = uses + 1 "
1105 -1, &_curr_repo->stmt_dup_increm, NULL)
1106 /* Prepare decrement dup statement. */
1107 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1109 "set uses = uses - 1 "
1111 -1, &_curr_repo->stmt_dup_decrem, NULL)
1112 /* Prepare delete dup statement. */
1113 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1115 "where hash = ? and uses <= 0",
1116 -1, &_curr_repo->stmt_dup_delete, NULL)
1118 /* Prepare begin-transaction statement. */
1119 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1120 "begin transaction",
1121 -1, &_curr_repo->stmt_trans_begin, NULL)
1122 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1123 "commit transaction",
1124 -1, &_curr_repo->stmt_trans_commit, NULL)
1125 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1126 "rollback transaction", -1,
1127 &_curr_repo->stmt_trans_rollback, NULL))
1129 gchar buffer[BUFFER_SIZE];
1130 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
1131 _("Failed to open map database for repository"),
1132 sqlite3_errmsg(_curr_repo->db),
1133 _("Downloaded maps will not be cached."));
1134 sqlite3_close(_curr_repo->db);
1135 _curr_repo->db = NULL;
1136 popup_error(_window, buffer);
1139 /* initialize all databases for all layers */
1140 repo_p = _curr_repo;
1142 if (repo_p->db_filename && *repo_p->db_filename
1143 && repo_make_db (repo_p))
1144 repo_p->db = gdbm_open(repo_p->db_filename,
1145 0, GDBM_WRCREAT | GDBM_FAST, 0644, NULL);
1146 repo_p = repo_p->layers;
1151 gchar buffer[BUFFER_SIZE];
1152 snprintf(buffer, sizeof(buffer), "%s\n%s",
1153 _("Failed to open map database for repository"),
1154 _("Downloaded maps will not be cached."));
1155 _curr_repo->db = NULL;
1156 popup_error(_window, buffer);
1162 _curr_repo->db = NULL;
1164 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1169 gchar buffer[BUFFER_SIZE];
1170 snprintf(buffer, sizeof(buffer), "%s: %s",
1171 _("Unable to create map database for repository"), rd->name);
1172 popup_error(_window, buffer);
1174 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1182 * 1. base == layer, or
1183 * 2. layer is sublayer of base
1185 gboolean repo_is_layer (RepoData* base, RepoData* layer)
1190 base = base->layers;
1198 * Given a wms uri pattern, compute the coordinate transformation and
1200 * 'proj' is used for the conversion
1203 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
1205 gint system_retcode;
1206 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
1209 gdouble lon1, lat1, lon2, lat2;
1211 gchar *widthstr = strcasestr(uri,"WIDTH=");
1212 gchar *heightstr = strcasestr(uri,"HEIGHT=");
1213 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
1214 gchar *srsstre = strchr(srsstr,'&');
1215 vprintf("%s()\n", __PRETTY_FUNCTION__);
1217 /* missing: test if found */
1219 strncpy(srs+4,srsstr+8,256);
1220 /* missing: test srsstre-srsstr < 526 */
1221 srs[srsstre-srsstr-4] = 0;
1222 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
1224 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
1225 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
1227 unit2latlon(tile2zunit(tilex,zoomlevel)
1228 - pixel2zunit(dwidth/2,zoomlevel),
1229 tile2zunit(tiley+1,zoomlevel)
1230 + pixel2zunit((dheight+1)/2,zoomlevel),
1233 unit2latlon(tile2zunit(tilex+1,zoomlevel)
1234 + pixel2zunit((dwidth+1)/2,zoomlevel),
1235 tile2zunit(tiley,zoomlevel)
1236 - pixel2zunit(dheight/2,zoomlevel),
1239 setlocale(LC_NUMERIC, "C");
1241 snprintf(cmd, sizeof(cmd),
1242 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
1243 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
1244 " > /tmp/tmpcs2cs ",
1245 lon1, lat1, lon2, lat2, srs);
1246 vprintf("Running command: %s\n", cmd);
1247 system_retcode = system(cmd);
1250 g_printerr("cs2cs returned error code %d\n",
1251 WEXITSTATUS(system_retcode));
1252 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
1253 g_printerr("Cannot open results of conversion\n");
1254 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
1255 &lon1, &lat1, cmd, &lon2, &lat2))
1257 g_printerr("Wrong conversion\n");
1263 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
1266 setlocale(LC_NUMERIC, "");
1268 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
1274 * Given the xyz coordinates of our map coordinate system, write the qrst
1275 * quadtree coordinates to buffer.
1278 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
1279 gchar *buffer, const gchar initial,
1280 const gchar *const quadrant)
1282 gchar *ptr = buffer;
1284 vprintf("%s()\n", __PRETTY_FUNCTION__);
1289 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
1291 gint xbit = (x >> n) & 1;
1292 gint ybit = (y >> n) & 1;
1293 *ptr++ = quadrant[xbit + 2 * ybit];
1296 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1300 * Construct the URL that we should fetch, based on the current URI format.
1301 * This method works differently depending on if a "%s" string is present in
1302 * the URI format, since that would indicate a quadtree-based map coordinate
1306 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
1309 vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1310 repo, zoom, tilex, tiley);
1314 retval = g_strdup_printf(repo->url,
1315 tilex, tiley, zoom - (MAX_ZOOM - 16));
1318 case REPOTYPE_XYZ_INV:
1319 retval = g_strdup_printf(repo->url,
1320 MAX_ZOOM + 1 - zoom, tilex, tiley);
1323 case REPOTYPE_XYZ_SIGNED:
1324 retval = g_strdup_printf(repo->url,
1326 (1 << (MAX_ZOOM - zoom)) - tiley - 1,
1327 zoom - (MAX_ZOOM - 17));
1330 case REPOTYPE_QUAD_QRST:
1332 gchar location[MAX_ZOOM + 2];
1333 map_convert_coords_to_quadtree_string(
1334 tilex, tiley, zoom, location, 't', "qrts");
1335 retval = g_strdup_printf(repo->url, location);
1339 case REPOTYPE_QUAD_ZERO:
1341 /* This is a zero-based quadtree URI. */
1342 gchar location[MAX_ZOOM + 2];
1343 map_convert_coords_to_quadtree_string(
1344 tilex, tiley, zoom, location, '\0', "0123");
1345 retval = g_strdup_printf(repo->url, location);
1350 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
1354 retval = g_strdup(repo->url);
1357 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
1362 mapdb_initiate_update_banner_idle()
1364 if(!_download_banner && _num_downloads != _curr_download)
1366 _download_banner = hildon_banner_show_progress(
1367 _window, NULL, _("Processing Maps"));
1368 /* If we're not connected, then hide the banner immediately. It will
1369 * be unhidden if/when we're connected. */
1370 if(!_conic_is_connected)
1371 gtk_widget_hide(_download_banner);
1377 * Initiate a download of the given xyz coordinates using the given buffer
1378 * as the URL. If the map already exists on disk, or if we are already
1379 * downloading the map, then this method does nothing.
1382 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
1383 gint update_type, gint batch_id, gint priority,
1384 ThreadLatch *refresh_latch)
1387 MapUpdateTask *old_mut;
1388 gboolean is_replacing = FALSE;
1389 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1390 repo->name, zoom, tilex, tiley, update_type);
1392 mut = g_slice_new(MapUpdateTask);
1395 /* Could not allocate memory. */
1396 g_printerr("Out of memory in allocation of update task #%d\n",
1397 _num_downloads + 1);
1403 mut->update_type = update_type;
1404 mut->layer_level = repo->layer_level;
1406 /* Lock the mutex if this is an auto-update. */
1407 if(update_type == MAP_UPDATE_AUTO)
1408 g_mutex_lock(_mut_priority_mutex);
1409 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
1411 /* Check if new mut is in a newer batch that the old mut.
1412 * We use vfs_result to indicate a MUT that is already in the process
1413 * of being downloaded. */
1414 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
1416 /* It is, so remove the old one so we can re-add this one. */
1417 g_hash_table_remove(_mut_exists_table, old_mut);
1418 g_tree_remove(_mut_priority_tree, old_mut);
1419 g_slice_free(MapUpdateTask, old_mut);
1420 is_replacing = TRUE;
1424 /* It's not, so just ignore it. */
1425 if(update_type == MAP_UPDATE_AUTO)
1426 g_mutex_unlock(_mut_priority_mutex);
1427 g_slice_free(MapUpdateTask, mut);
1428 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
1433 g_hash_table_insert(_mut_exists_table, mut, mut);
1436 mut->refresh_latch = refresh_latch;
1437 mut->priority = priority;
1438 mut->batch_id = batch_id;
1440 mut->vfs_result = -1;
1442 g_tree_insert(_mut_priority_tree, mut, mut);
1444 /* Unlock the mutex if this is an auto-update. */
1445 if(update_type == MAP_UPDATE_AUTO)
1446 g_mutex_unlock(_mut_priority_mutex);
1450 /* Increment download count and (possibly) display banner. */
1451 if(++_num_downloads == 20 && !_download_banner)
1452 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
1454 /* This doesn't need to be thread-safe. Extras in the pool don't
1455 * really make a difference. */
1456 if(g_thread_pool_get_num_threads(_mut_thread_pool)
1457 < g_thread_pool_get_max_threads(_mut_thread_pool))
1458 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1461 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1466 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1475 printf("%s()\n", __PRETTY_FUNCTION__);
1477 /* Make sure things are inititalized. */
1480 while(conic_ensure_connected())
1483 gboolean refresh_sent = FALSE, layer_tile;
1484 MapUpdateTask *mut = NULL;
1486 /* Get the next MUT from the mut tree. */
1487 g_mutex_lock(_mut_priority_mutex);
1488 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1491 /* No more MUTs to process. Return. */
1492 g_mutex_unlock(_mut_priority_mutex);
1495 /* Mark this MUT as "in-progress". */
1496 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1497 g_tree_remove(_mut_priority_tree, mut);
1498 g_mutex_unlock(_mut_priority_mutex);
1500 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1501 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1503 layer_tile = mut->repo != _curr_repo && repo_is_layer (_curr_repo, mut->repo);
1505 if (mut->repo != _curr_repo && !layer_tile)
1507 /* Do nothing, except report that there is no error. */
1508 mut->vfs_result = GNOME_VFS_OK;
1510 else if(mut->update_type == MAP_UPDATE_DELETE)
1512 /* Easy - just delete the entry from the database. We don't care
1513 * about failures (sorry). */
1515 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1517 /* Report that there is no error. */
1518 mut->vfs_result = GNOME_VFS_OK;
1520 else for(retries = mut->repo->layer_level ? 1 : INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1522 gboolean exists = FALSE;
1526 GdkPixbufLoader *loader;
1528 gint zoom, tilex, tiley;
1529 GError *error = NULL;
1532 /* First check for existence. */
1533 exists = mut->repo->db
1534 ? mapdb_exists(mut->repo, mut->zoom,
1535 mut->tilex, mut->tiley)
1537 if(exists && mut->update_type == MAP_UPDATE_ADD)
1539 /* Map already exists, and we're not going to overwrite. */
1540 /* Report that there is no error. */
1541 mut->vfs_result = GNOME_VFS_OK;
1545 /* First check for existence. */
1546 if(mut->update_type == MAP_UPDATE_ADD)
1548 /* We don't want to overwrite, so check for existence. */
1549 /* Map already exists, and we're not going to overwrite. */
1550 if(mapdb_exists(mut->repo, mut->zoom,
1551 mut->tilex,mut->tiley))
1553 /* Report that there is no error. */
1554 mut->vfs_result = GNOME_VFS_OK;
1560 /* First, construct the URL from which we will get the data. */
1561 src_url = map_construct_url(mut->repo, mut->zoom,
1562 mut->tilex, mut->tiley);
1564 /* Now, attempt to read the entire contents of the URL. */
1565 mut->vfs_result = gnome_vfs_read_entire_file(
1566 src_url, &size, &bytes);
1568 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1571 printf("Error reading URL: %s\n",
1572 gnome_vfs_result_to_string(mut->vfs_result));
1576 /* usleep(100000); DEBUG */
1578 /* Attempt to parse the bytes into a pixbuf. */
1579 loader = gdk_pixbuf_loader_new();
1580 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1581 gdk_pixbuf_loader_close(loader, &error);
1582 if(error || (NULL == (mut->pixbuf = g_object_ref(
1583 gdk_pixbuf_loader_get_pixbuf(loader)))))
1585 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1587 g_object_unref(mut->pixbuf);
1590 g_object_unref(loader);
1591 printf("Error parsing pixbuf: %s\n",
1592 error ? error->message : "?");
1595 g_object_unref(loader);
1597 /* attach timestamp with loaded pixbuf */
1601 GError* error = NULL;
1604 sprintf (ts_val, "%u", (unsigned int)time (NULL));
1606 /* update bytes with new, timestamped pixbuf */
1607 if (gdk_pixbuf_save_to_buffer (mut->pixbuf, &new_bytes, &new_size, "png", &error, layer_timestamp_key, ts_val, NULL))
1615 /* Copy database-relevant mut data before we release it. */
1621 /* Pass the mut to the GTK thread for redrawing, but only if a
1622 * redraw isn't already in the pipeline. */
1623 if(mut->refresh_latch)
1625 /* Wait until the latch is open. */
1626 g_mutex_lock(mut->refresh_latch->mutex);
1627 while(!mut->refresh_latch->is_open)
1629 g_cond_wait(mut->refresh_latch->cond,
1630 mut->refresh_latch->mutex);
1632 /* Latch is open. Decrement the number of waiters and
1633 * check if we're the last waiter to run. */
1634 if(mut->refresh_latch->is_done_adding_tasks)
1636 if(++mut->refresh_latch->num_done
1637 == mut->refresh_latch->num_tasks)
1639 /* Last waiter. Free the latch resources. */
1640 g_mutex_unlock(mut->refresh_latch->mutex);
1641 g_cond_free(mut->refresh_latch->cond);
1642 g_mutex_free(mut->refresh_latch->mutex);
1643 g_slice_free(ThreadLatch, mut->refresh_latch);
1644 mut->refresh_latch = NULL;
1648 /* Not the last waiter. Signal the next waiter.*/
1649 g_cond_signal(mut->refresh_latch->cond);
1650 g_mutex_unlock(mut->refresh_latch->mutex);
1654 g_mutex_unlock(mut->refresh_latch->mutex);
1657 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1658 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1659 refresh_sent = TRUE;
1661 /* DO NOT USE mut FROM THIS POINT ON. */
1663 /* Also attempt to add to the database. */
1664 mapdb_update(exists, repo, zoom,
1665 tilex, tiley, bytes, size);
1673 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1674 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1677 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1682 mut_exists_hashfunc(const MapUpdateTask *a)
1684 gint sum = a->zoom + a->tilex + a->tiley + a->update_type + a->layer_level;
1685 return g_int_hash(&sum);
1689 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1691 return (a->tilex == b->tilex
1692 && a->tiley == b->tiley
1693 && a->zoom == b->zoom
1694 && a->update_type == b->update_type
1695 && a->layer_level == b->layer_level);
1699 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1701 /* The update_type enum is sorted in order of ascending priority. */
1702 gint diff = (b->update_type - a->update_type);
1705 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1708 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1711 diff = (a->layer_level - b->layer_level); /* Lower layers first. */
1715 /* At this point, we don't care, so just pick arbitrarily. */
1716 diff = (a->tilex - b->tilex);
1719 diff = (a->tiley - b->tiley);
1722 return (a->zoom - b->zoom);
1726 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1728 printf("%s()\n", __PRETTY_FUNCTION__);
1729 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1730 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1731 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1736 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1740 printf("%s()\n", __PRETTY_FUNCTION__);
1742 dialog = GTK_WIDGET(
1743 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1744 GTK_FILE_CHOOSER_ACTION_SAVE));
1746 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1747 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1749 /* Work around a bug in HildonFileChooserDialog. */
1750 basename = g_path_get_basename(
1751 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1752 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1753 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1755 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1757 gchar *filename = gtk_file_chooser_get_filename(
1758 GTK_FILE_CHOOSER(dialog));
1759 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1763 gtk_widget_destroy(dialog);
1765 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1770 repoman_compact_complete_idle(CompactInfo *ci)
1772 printf("%s()\n", __PRETTY_FUNCTION__);
1774 gtk_widget_destroy(GTK_WIDGET(ci->banner));
1775 popup_error(ci->dialog, ci->status_msg);
1776 gtk_widget_destroy(ci->dialog);
1779 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1784 thread_repoman_compact(CompactInfo *ci)
1787 printf("%s()\n", __PRETTY_FUNCTION__);
1789 if(!(db = gdbm_open((gchar*)ci->db_filename, 0, GDBM_WRITER | GDBM_FAST,
1791 ci->status_msg = _("Failed to open map database for compacting.");
1794 if(gdbm_reorganize(db))
1795 ci->status_msg = _("An error occurred while trying to "
1796 "compact the database.");
1798 ci->status_msg = _("Successfully compacted database.");
1802 g_idle_add((GSourceFunc)repoman_compact_complete_idle, ci);
1804 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1808 repoman_dialog_compact(GtkWidget *widget, BrowseInfo *browse_info)
1812 printf("%s()\n", __PRETTY_FUNCTION__);
1814 ci = g_new0(CompactInfo, 1);
1816 ci->dialog = gtk_dialog_new_with_buttons(_("Compact Database"),
1817 GTK_WINDOW(browse_info->dialog), GTK_DIALOG_MODAL,
1818 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1819 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1822 sw = gtk_scrolled_window_new (NULL, NULL);
1823 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1824 GTK_SHADOW_ETCHED_IN);
1825 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1828 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ci->dialog)->vbox),
1831 gtk_container_add(GTK_CONTAINER(sw), ci->txt = gtk_text_view_new());
1832 gtk_text_view_set_editable(GTK_TEXT_VIEW(ci->txt), FALSE);
1833 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ci->txt), FALSE);
1834 gtk_text_buffer_set_text(
1835 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1836 _("Generally, deleted maps create an empty space in the "
1837 "database that is later reused when downloading new maps. "
1838 "Compacting the database reorganizes it such that all "
1839 "that blank space is eliminated. This is the only way "
1840 "that the size of the database can decrease.\n"
1841 "This reorganization requires creating a new file and "
1842 "inserting all the maps in the old database file into the "
1843 "new file. The new file is then renamed to the same name "
1844 "as the old file and dbf is updated to contain all the "
1845 "correct information about the new file. Note that this "
1846 "can require free space on disk of an amount up to the size "
1847 "of the map database.\n"
1848 "This process may take several minutes, especially if "
1849 "your map database is large. As a rough estimate, you can "
1850 "expect to wait approximately 2-5 seconds per megabyte of "
1851 "map data (34-85 minutes per gigabyte). There is no progress "
1852 "indicator, although you can watch the new file grow in any "
1853 "file manager. Do not attempt to close Maemo Mapper while "
1854 "the compacting operation is in progress."),
1858 gtk_text_buffer_get_iter_at_offset(
1859 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1861 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ci->txt),
1862 &iter, 0.0, FALSE, 0, 0);
1865 gtk_widget_set_size_request(GTK_WIDGET(sw), 600, 200);
1866 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(ci->txt), GTK_WRAP_WORD);
1868 gtk_widget_show_all(ci->dialog);
1870 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(ci->dialog)))
1872 gtk_widget_set_sensitive(GTK_DIALOG(ci->dialog)->action_area, FALSE);
1873 ci->db_filename = gtk_entry_get_text(GTK_ENTRY(browse_info->txt));
1874 ci->banner = hildon_banner_show_animation(ci->dialog, NULL,
1875 _("Compacting database..."));
1877 g_thread_create((GThreadFunc)thread_repoman_compact, ci, FALSE, NULL);
1881 gtk_widget_destroy(ci->dialog);
1884 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1888 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1890 static GtkWidget *hbox = NULL;
1891 static GtkWidget *label = NULL;
1892 static GtkWidget *txt_name = NULL;
1893 static GtkWidget *dialog = NULL;
1894 printf("%s()\n", __PRETTY_FUNCTION__);
1898 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1899 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1900 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1901 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1904 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1905 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1907 gtk_box_pack_start(GTK_BOX(hbox),
1908 label = gtk_label_new(_("Name")),
1910 gtk_box_pack_start(GTK_BOX(hbox),
1911 txt_name = gtk_entry_new(),
1916 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1917 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1918 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1921 gtk_widget_show_all(dialog);
1923 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1925 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1926 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1928 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1929 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1930 active, g_strdup(rei->name));
1931 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1932 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1936 gtk_widget_hide(dialog);
1938 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1943 repoman_delete(RepoManInfo *rmi, gint index)
1945 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1946 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1947 rmi->repo_edits = g_list_remove_link(
1949 g_list_nth(rmi->repo_edits, index));
1953 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1957 printf("%s()\n", __PRETTY_FUNCTION__);
1959 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1960 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1963 popup_error(rmi->dialog,
1964 _("Cannot delete the last repository - there must be at"
1965 " lease one repository."));
1966 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1970 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1971 _("Confirm delete of repository"),
1972 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1974 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1976 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1978 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1979 repoman_delete(rmi, active);
1980 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1984 gtk_widget_destroy(confirm);
1989 static RepoEditInfo*
1990 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
1996 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
1997 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
2002 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
2003 vbox = gtk_vbox_new(FALSE, 4),
2004 gtk_label_new(name));
2006 /* Prevent destruction of notebook page, because the destruction causes
2007 * a seg fault (!?!?) */
2008 gtk_object_ref(GTK_OBJECT(vbox));
2010 gtk_box_pack_start(GTK_BOX(vbox),
2011 table = gtk_table_new(2, 2, FALSE),
2013 /* Map download URI. */
2014 gtk_table_attach(GTK_TABLE(table),
2015 label = gtk_label_new(_("URL Format")),
2016 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2017 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2018 gtk_table_attach(GTK_TABLE(table),
2019 rei->txt_url = gtk_entry_new(),
2020 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2022 /* Map Directory. */
2023 gtk_table_attach(GTK_TABLE(table),
2024 label = gtk_label_new(_("Cache DB")),
2025 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2026 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2027 gtk_table_attach(GTK_TABLE(table),
2028 hbox = gtk_hbox_new(FALSE, 4),
2029 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2030 gtk_box_pack_start(GTK_BOX(hbox),
2031 rei->txt_db_filename = gtk_entry_new(),
2033 gtk_box_pack_start(GTK_BOX(hbox),
2034 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
2036 gtk_box_pack_start(GTK_BOX(hbox),
2037 rei->btn_compact = gtk_button_new_with_label(_("Compact...")),
2040 /* Initialize cache dir */
2042 gchar buffer[BUFFER_SIZE];
2043 snprintf(buffer, sizeof(buffer), "%s.db", name);
2044 gchar *db_base = gnome_vfs_expand_initial_tilde(
2045 REPO_DEFAULT_CACHE_BASE);
2046 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
2048 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
2049 g_free(db_filename);
2053 gtk_box_pack_start(GTK_BOX(vbox),
2054 table = gtk_table_new(3, 2, FALSE),
2057 /* Download Zoom Steps. */
2058 gtk_table_attach(GTK_TABLE(table),
2059 label = gtk_label_new(_("Download Zoom Steps")),
2060 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2061 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2062 gtk_table_attach(GTK_TABLE(table),
2063 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2064 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
2065 gtk_container_add(GTK_CONTAINER(label),
2066 rei->num_dl_zoom_steps = hildon_controlbar_new());
2067 hildon_controlbar_set_range(
2068 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
2069 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2070 REPO_DEFAULT_DL_ZOOM_STEPS);
2071 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
2073 /* Download Zoom Steps. */
2074 gtk_table_attach(GTK_TABLE(table),
2075 label = gtk_label_new(_("View Zoom Steps")),
2076 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2077 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2078 gtk_table_attach(GTK_TABLE(table),
2079 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2080 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
2081 gtk_container_add(GTK_CONTAINER(label),
2082 rei->num_view_zoom_steps = hildon_controlbar_new());
2083 hildon_controlbar_set_range(
2084 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
2085 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2086 REPO_DEFAULT_VIEW_ZOOM_STEPS);
2087 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
2089 gtk_table_attach(GTK_TABLE(table),
2090 label = gtk_vseparator_new(),
2091 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
2094 gtk_table_attach(GTK_TABLE(table),
2095 rei->chk_double_size = gtk_check_button_new_with_label(
2096 _("Double Pixels")),
2097 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
2098 gtk_toggle_button_set_active(
2099 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
2102 gtk_table_attach(GTK_TABLE(table),
2103 rei->chk_nextable = gtk_check_button_new_with_label(
2105 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
2106 gtk_toggle_button_set_active(
2107 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
2109 /* Downloadable Zoom Levels. */
2110 gtk_table_attach(GTK_TABLE(table),
2111 label = gtk_label_new(_("Downloadable Zooms:")),
2112 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2113 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2114 gtk_table_attach(GTK_TABLE(table),
2115 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2116 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
2117 gtk_container_add(GTK_CONTAINER(label),
2118 hbox = gtk_hbox_new(FALSE, 4));
2119 gtk_box_pack_start(GTK_BOX(hbox),
2120 label = gtk_label_new(_("Min.")),
2122 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2123 gtk_box_pack_start(GTK_BOX(hbox),
2124 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2126 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
2127 gtk_box_pack_start(GTK_BOX(hbox),
2128 label = gtk_label_new(""),
2130 gtk_box_pack_start(GTK_BOX(hbox),
2131 label = gtk_label_new(_("Max.")),
2133 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2134 gtk_box_pack_start(GTK_BOX(hbox),
2135 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2137 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
2139 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
2141 /* Connect signals. */
2142 rei->browse_info.dialog = rmi->dialog;
2143 rei->browse_info.txt = rei->txt_db_filename;
2144 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
2145 G_CALLBACK(repoman_dialog_browse),
2147 g_signal_connect(G_OBJECT(rei->btn_compact), "clicked",
2148 G_CALLBACK(repoman_dialog_compact),
2151 gtk_widget_show_all(vbox);
2153 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
2154 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
2155 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
2156 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
2159 /* newly created repos keep this NULL in rei, indicating
2160 that layes cannot be added so far */
2163 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2168 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
2170 static GtkWidget *hbox = NULL;
2171 static GtkWidget *label = NULL;
2172 static GtkWidget *txt_name = NULL;
2173 static GtkWidget *dialog = NULL;
2174 printf("%s()\n", __PRETTY_FUNCTION__);
2178 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
2179 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
2180 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2181 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2184 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2185 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2187 gtk_box_pack_start(GTK_BOX(hbox),
2188 label = gtk_label_new(_("Name")),
2190 gtk_box_pack_start(GTK_BOX(hbox),
2191 txt_name = gtk_entry_new(),
2195 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2197 gtk_widget_show_all(dialog);
2199 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2201 repoman_dialog_add_repo(rmi,
2202 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2206 gtk_widget_hide(dialog);
2208 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2213 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
2216 printf("%s()\n", __PRETTY_FUNCTION__);
2218 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
2219 _("Replace all repositories with the default repository?"));
2221 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2223 /* First, delete all existing repositories. */
2224 while(rmi->repo_edits)
2225 repoman_delete(rmi, 0);
2227 /* Now, add the default repository. */
2228 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
2230 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
2231 REPO_DEFAULT_MAP_URI);
2233 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
2235 gtk_widget_destroy(confirm);
2237 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2245 printf("%s()\n", __PRETTY_FUNCTION__);
2247 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
2248 _("Maemo Mapper will now download and add a list of "
2249 "possibly-duplicate repositories from the internet. "
2252 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2258 GnomeVFSResult vfs_result;
2259 printf("%s()\n", __PRETTY_FUNCTION__);
2261 /* Get repo config file from www.gnuite.com. */
2262 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2263 "http://www.gnuite.com/nokia770/maemo-mapper/"
2264 "repos-with-layers.txt",
2267 popup_error(_window,
2268 _("An error occurred while retrieving the repositories. "
2269 "The web service may be temporarily down."));
2270 g_printerr("Error while download repositories: %s\n",
2271 gnome_vfs_result_to_string(vfs_result));
2273 /* Parse each line as a reposotory. */
2276 RepoData *prev_repo = NULL;
2277 menu_maps_remove_repos();
2278 for(head = bytes; head && *head; head = tail)
2281 tail = strchr(head, '\n');
2284 rd = settings_parse_repo(head);
2285 if (rd->layer_level == 0) {
2286 _repo_list = g_list_append(_repo_list, rd);
2289 prev_repo->layers = rd;
2294 menu_maps_add_repos();
2298 gtk_widget_destroy(confirm);
2300 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2306 layer_get_page_index (RepoLayersInfo *rli, GtkTreeIter list_it)
2308 GtkTreePath *p1, *p2;
2312 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (rli->layers_store), &p);
2314 p1 = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &list_it);
2315 p2 = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &p);
2317 while (gtk_tree_path_compare (p1, p2) != 0) {
2318 gtk_tree_path_next (p2);
2322 gtk_tree_path_free (p1);
2323 gtk_tree_path_free (p2);
2330 layer_name_changed (GtkWidget *entry, LayerEditInfo *lei)
2333 GtkTreeSelection *selection;
2336 printf("%s()\n", __PRETTY_FUNCTION__);
2339 name = gtk_entry_get_text (GTK_ENTRY (entry));
2341 /* find selected entry in list view */
2342 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (lei->rli->layers_list));
2344 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2345 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2349 gtk_list_store_set (lei->rli->layers_store, &iter, 0, name, -1);
2351 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2357 layer_dialog_browse (GtkWidget *widget, LayerEditInfo *lei)
2361 printf("%s()\n", __PRETTY_FUNCTION__);
2363 dialog = GTK_WIDGET(
2364 hildon_file_chooser_dialog_new(GTK_WINDOW(lei->rli->dialog),
2365 GTK_FILE_CHOOSER_ACTION_SAVE));
2367 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
2368 gtk_entry_get_text(GTK_ENTRY(lei->txt_db)));
2370 /* Work around a bug in HildonFileChooserDialog. */
2371 basename = g_path_get_basename(
2372 gtk_entry_get_text(GTK_ENTRY(lei->txt_db)));
2373 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
2374 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
2376 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
2378 gchar *filename = gtk_file_chooser_get_filename(
2379 GTK_FILE_CHOOSER(dialog));
2380 gtk_entry_set_text(GTK_ENTRY(lei->txt_db), filename);
2384 gtk_widget_destroy(dialog);
2386 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2392 static LayerEditInfo*
2393 repoman_layers_add_layer (RepoLayersInfo *rli, gchar* name)
2395 LayerEditInfo *lei = g_new (LayerEditInfo, 1);
2400 GtkWidget *btn_browse;
2401 GtkTreeIter layers_iter;
2403 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
2407 rli->layer_edits = g_list_append (rli->layer_edits, lei);
2409 gtk_notebook_append_page (GTK_NOTEBOOK (rli->notebook), vbox = gtk_vbox_new (FALSE, 4),
2410 gtk_label_new (name));
2412 gtk_box_pack_start (GTK_BOX (vbox), table = gtk_table_new (4, 2, FALSE),
2416 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Name")),
2417 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
2418 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2419 gtk_table_attach (GTK_TABLE (table), lei->txt_name = gtk_entry_new (),
2420 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2421 gtk_entry_set_text (GTK_ENTRY (lei->txt_name), name);
2424 g_signal_connect(G_OBJECT(lei->txt_name), "changed", G_CALLBACK(layer_name_changed), lei);
2427 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("URL")),
2428 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
2429 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2430 gtk_table_attach (GTK_TABLE (table), lei->txt_url = gtk_entry_new (),
2431 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2434 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Cache DB")),
2435 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2436 gtk_misc_set_alignment (GTK_MISC (label), 1.f, 0.5f);
2437 gtk_table_attach (GTK_TABLE (table), hbox2 = gtk_hbox_new (FALSE, 4),
2438 1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2439 gtk_box_pack_start (GTK_BOX (hbox2), lei->txt_db = gtk_entry_new (),
2441 gtk_box_pack_start (GTK_BOX (hbox2), btn_browse = gtk_button_new_with_label (_("Browse...")),
2444 g_signal_connect(G_OBJECT(btn_browse), "clicked", G_CALLBACK(layer_dialog_browse), lei);
2447 gtk_table_attach (GTK_TABLE (table), label = gtk_label_new (_("Autofetch")),
2448 0, 1, 3, 4, GTK_FILL, 0, 2, 0);
2449 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2450 gtk_table_attach (GTK_TABLE (table), hbox2 = gtk_hbox_new (FALSE, 4),
2451 1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 0);
2452 gtk_box_pack_start (GTK_BOX (hbox2), lei->num_autofetch = hildon_number_editor_new (0, 120),
2454 gtk_box_pack_start (GTK_BOX (hbox2), label = gtk_label_new (_("min.")), FALSE, FALSE, 4);
2455 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2458 gtk_box_pack_start (GTK_BOX (vbox), lei->chk_visible = gtk_check_button_new_with_label (_("Layer is visible")),
2461 gtk_widget_show_all (vbox);
2463 /* Side list view with layers */
2464 gtk_list_store_append (rli->layers_store, &layers_iter);
2465 gtk_list_store_set (rli->layers_store, &layers_iter, 0, name, -1);
2467 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2475 repoman_layers_new (GtkWidget *widget, RepoLayersInfo *rli)
2477 static GtkWidget *hbox = NULL;
2478 static GtkWidget *label = NULL;
2479 static GtkWidget *txt_name = NULL;
2480 static GtkWidget *dialog = NULL;
2481 printf("%s()\n", __PRETTY_FUNCTION__);
2485 dialog = gtk_dialog_new_with_buttons(_("New Layer"),
2486 GTK_WINDOW(rli->dialog), GTK_DIALOG_MODAL,
2487 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2488 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2491 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2492 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2494 gtk_box_pack_start(GTK_BOX(hbox),
2495 label = gtk_label_new(_("Name")),
2497 gtk_box_pack_start(GTK_BOX(hbox),
2498 txt_name = gtk_entry_new(),
2502 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2504 gtk_widget_show_all(dialog);
2506 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2508 repoman_layers_add_layer(rli,
2509 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2513 gtk_widget_hide(dialog);
2514 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2520 repoman_layers_del (GtkWidget *widget, RepoLayersInfo *rli)
2523 GtkTreeSelection *selection;
2526 printf("%s()\n", __PRETTY_FUNCTION__);
2528 /* delete list item */
2529 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2531 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2532 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2536 index = layer_get_page_index (rli, iter);
2537 gtk_list_store_remove (rli->layers_store, &iter);
2539 rli->layer_edits = g_list_remove_link (rli->layer_edits, g_list_nth (rli->layer_edits, index));
2541 /* delete notebook page */
2542 gtk_notebook_remove_page (GTK_NOTEBOOK (rli->notebook), index);
2544 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2550 repoman_layers_up (GtkWidget *widget, RepoLayersInfo *rli)
2552 GtkTreeSelection *selection;
2553 GtkTreeIter iter, iter2;
2559 printf("%s()\n", __PRETTY_FUNCTION__);
2561 /* find selected entry in list view */
2562 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2564 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2565 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2570 path = gtk_tree_model_get_path (GTK_TREE_MODEL (rli->layers_store), &iter);
2571 if (!gtk_tree_path_prev (path) || !gtk_tree_model_get_iter (GTK_TREE_MODEL (rli->layers_store), &iter, path)) {
2572 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2576 gtk_tree_path_free (path);
2579 gtk_list_store_move_before (rli->layers_store, &iter2, &iter);
2581 /* reorder notebook tabs */
2582 page = gtk_notebook_get_current_page (GTK_NOTEBOOK (rli->notebook));
2583 gtk_notebook_reorder_child (GTK_NOTEBOOK (rli->notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (rli->notebook), page), page-1);
2585 /* reorder layer edits */
2586 list_elem = g_list_nth (rli->layer_edits, page);
2587 lei = list_elem->data;
2588 rli->layer_edits = g_list_remove_link (rli->layer_edits, list_elem);
2589 rli->layer_edits = g_list_insert (rli->layer_edits, lei, page-1);
2591 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2597 repoman_layers_dn (GtkWidget *widget, RepoLayersInfo *rli)
2599 GtkTreeSelection *selection;
2600 GtkTreeIter iter, iter2;
2605 printf("%s()\n", __PRETTY_FUNCTION__);
2607 /* find selected entry in list view */
2608 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli->layers_list));
2610 if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
2611 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2616 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (rli->layers_store), &iter)) {
2617 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2622 gtk_list_store_move_after (rli->layers_store, &iter2, &iter);
2624 /* reorder notebook tabs */
2625 page = gtk_notebook_get_current_page (GTK_NOTEBOOK (rli->notebook));
2626 gtk_notebook_reorder_child (GTK_NOTEBOOK (rli->notebook), gtk_notebook_get_nth_page (GTK_NOTEBOOK (rli->notebook), page), page+1);
2628 /* reorder layer edits */
2629 list_elem = g_list_nth (rli->layer_edits, page);
2630 lei = list_elem->data;
2631 rli->layer_edits = g_list_remove_link (rli->layer_edits, list_elem);
2632 rli->layer_edits = g_list_insert (rli->layer_edits, lei, page+1);
2634 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2640 repoman_layer_selected (GtkTreeSelection *selection, RepoLayersInfo *rli)
2644 printf("%s()\n", __PRETTY_FUNCTION__);
2646 if (!gtk_tree_selection_get_selected (selection, NULL, &cur)) {
2647 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2651 gtk_notebook_set_current_page (GTK_NOTEBOOK (rli->notebook), layer_get_page_index (rli, cur));
2653 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2659 repoman_layers(GtkWidget *widget, RepoManInfo *rmi)
2661 GtkWidget *hbox = NULL;
2662 GtkWidget *layers_vbox = NULL;
2663 GtkWidget *buttons_hbox = NULL;
2665 GtkCellRenderer *layers_rendeder = NULL;
2666 GtkTreeViewColumn *layers_column = NULL;
2667 GtkTreeSelection *selection;
2669 /* layers buttons */
2670 GtkWidget *btn_new = NULL;
2671 GtkWidget *btn_del = NULL;
2672 GtkWidget *btn_up = NULL;
2673 GtkWidget *btn_dn = NULL;
2675 const char* t_header = _("Manage layers [%s]");
2676 char* header = NULL;
2677 RepoEditInfo* rei = NULL;
2679 gint curr_repo_index = gtk_combo_box_get_active (GTK_COMBO_BOX (rmi->cmb_repos));
2682 printf("%s()\n", __PRETTY_FUNCTION__);
2684 if (curr_repo_index < 0) {
2685 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
2689 rei = g_list_nth_data (rmi->repo_edits, curr_repo_index);
2692 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
2696 /* check that rei have repo data structure. If it haven't, it means that repository have just
2697 added, so report about this */
2699 GtkWidget *msg = hildon_note_new_information ( GTK_WINDOW (rmi->dialog),
2700 _("You cannot add layers to not saved repository,\nsorry. So, press ok in repository manager\n"
2701 "and open this dialog again."));
2703 gtk_dialog_run (GTK_DIALOG (msg));
2704 gtk_widget_destroy (msg);
2706 vprintf("%s(): return FALSE (3)\n", __PRETTY_FUNCTION__);
2710 header = g_malloc (strlen (t_header) + strlen (rei->name));
2711 sprintf (header, t_header, rei->name);
2713 printf ("Creating dialog with header: %s\n", header);
2715 rli.layer_edits = NULL;
2716 rli.dialog = gtk_dialog_new_with_buttons (header, GTK_WINDOW (rmi->dialog), GTK_DIALOG_MODAL,
2717 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2718 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
2720 rli.layers_store = gtk_list_store_new (1, G_TYPE_STRING);
2721 rli.layers_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (rli.layers_store));
2722 layers_rendeder = gtk_cell_renderer_text_new ();
2723 layers_column = gtk_tree_view_column_new_with_attributes ("Column", layers_rendeder, "text", 0, NULL);
2724 gtk_tree_view_append_column (GTK_TREE_VIEW (rli.layers_list), layers_column);
2726 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (rli.layers_list));
2728 frame = gtk_frame_new (NULL);
2729 gtk_container_add (GTK_CONTAINER (frame), rli.layers_list);
2730 gtk_widget_set_size_request (frame, -1, 100);
2732 /* beside layers list with have buttons on bottom */
2733 layers_vbox = gtk_vbox_new (FALSE, 4);
2734 gtk_box_pack_start (GTK_BOX (layers_vbox), frame, TRUE, TRUE, 0);
2735 gtk_box_pack_start (GTK_BOX (layers_vbox), buttons_hbox = gtk_hbox_new (FALSE, 4), FALSE, FALSE, 0);
2738 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_new = gtk_button_new_with_label (_("New")), FALSE, FALSE, 0);
2739 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_del = gtk_button_new_with_label (_("Del")), FALSE, FALSE, 0);
2740 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_up = gtk_button_new_with_label (_("Up")), FALSE, FALSE, 0);
2741 gtk_box_pack_start (GTK_BOX (buttons_hbox), btn_dn = gtk_button_new_with_label (_("Dn")), FALSE, FALSE, 0);
2744 g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(repoman_layer_selected), &rli);
2745 g_signal_connect(G_OBJECT(btn_new), "clicked", G_CALLBACK(repoman_layers_new), &rli);
2746 g_signal_connect(G_OBJECT(btn_del), "clicked", G_CALLBACK(repoman_layers_del), &rli);
2747 g_signal_connect(G_OBJECT(btn_up), "clicked", G_CALLBACK(repoman_layers_up), &rli);
2748 g_signal_connect(G_OBJECT(btn_dn), "clicked", G_CALLBACK(repoman_layers_dn), &rli);
2750 /* notebook with layers' attributes */
2751 rli.notebook = gtk_notebook_new ();
2753 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rli.notebook), FALSE);
2754 gtk_notebook_set_show_border(GTK_NOTEBOOK(rli.notebook), FALSE);
2756 /* walk through all layers and add notebook pages */
2757 rd = rei->repo->layers;
2759 LayerEditInfo *lei = repoman_layers_add_layer (&rli, rd->name);
2761 gtk_entry_set_text (GTK_ENTRY (lei->txt_url), rd->url);
2762 gtk_entry_set_text (GTK_ENTRY (lei->txt_db), rd->db_filename);
2763 hildon_number_editor_set_value (HILDON_NUMBER_EDITOR (lei->num_autofetch), rd->layer_refresh_interval);
2764 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lei->chk_visible), rd->layer_enabled);
2769 /* pack all widgets together */
2770 hbox = gtk_hbox_new (FALSE, 4);
2772 gtk_box_pack_start (GTK_BOX (hbox), layers_vbox, TRUE, TRUE, 4);
2773 gtk_box_pack_start (GTK_BOX (hbox), rli.notebook, TRUE, TRUE, 4);
2775 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (rli.dialog)->vbox), hbox, FALSE, FALSE, 4);
2777 gtk_widget_show_all (rli.dialog);
2779 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run (GTK_DIALOG (rli.dialog)))
2785 menu_layers_remove_repos ();
2787 /* iterate over notebook's pages and build layers */
2788 /* keep list in memory in case downloads use it (TODO: reference counting) */
2789 rdp = &rei->repo->layers;
2792 for (i = 0, curr = rli.layer_edits; curr; curr = curr->next, i++) {
2793 LayerEditInfo *lei = curr->data;
2795 rd = g_new0 (RepoData, 1);
2798 rd->name = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_name)));
2799 rd->url = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_url)));
2800 rd->db_filename = g_strdup (gtk_entry_get_text (GTK_ENTRY (lei->txt_db)));
2801 rd->layer_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lei->chk_visible));
2802 rd->layer_refresh_interval = hildon_number_editor_get_value (HILDON_NUMBER_EDITOR (lei->num_autofetch));
2803 rd->layer_refresh_countdown = rd->layer_refresh_interval;
2804 rd->layer_level = i+1;
2806 rd->dl_zoom_steps = rei->repo->dl_zoom_steps;
2807 rd->view_zoom_steps = rei->repo->view_zoom_steps;
2808 rd->double_size = rei->repo->double_size;
2809 rd->nextable = rei->repo->nextable;
2810 rd->min_zoom = rei->repo->min_zoom;
2811 rd->max_zoom = rei->repo->max_zoom;
2817 menu_layers_add_repos ();
2818 repo_set_curr(_curr_repo);
2821 map_refresh_mark (TRUE);
2825 gtk_widget_destroy (rli.dialog);
2827 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2835 static RepoManInfo rmi;
2836 static GtkWidget *dialog = NULL;
2837 static GtkWidget *hbox = NULL;
2838 static GtkWidget *btn_rename = NULL;
2839 static GtkWidget *btn_delete = NULL;
2840 static GtkWidget *btn_new = NULL;
2841 static GtkWidget *btn_reset = NULL;
2842 static GtkWidget *btn_layers = NULL;
2843 gint i, curr_repo_index = 0;
2845 printf("%s()\n", __PRETTY_FUNCTION__);
2849 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
2850 _("Manage Repositories"),
2851 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2852 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2855 /* Enable the help button. */
2857 hildon_help_dialog_help_enable(
2859 ossohelp_dialog_help_enable(
2861 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
2864 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2865 btn_reset = gtk_button_new_with_label(_("Reset...")));
2866 g_signal_connect(G_OBJECT(btn_reset), "clicked",
2867 G_CALLBACK(repoman_reset), &rmi);
2869 /* Layers button. */
2870 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2871 btn_layers = gtk_button_new_with_label(_("Layers...")));
2872 g_signal_connect(G_OBJECT(btn_layers), "clicked",
2873 G_CALLBACK(repoman_layers), &rmi);
2875 /* Cancel button. */
2876 gtk_dialog_add_button(GTK_DIALOG(dialog),
2877 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2879 hbox = gtk_hbox_new(FALSE, 4);
2881 gtk_box_pack_start(GTK_BOX(hbox),
2882 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
2884 gtk_box_pack_start(GTK_BOX(hbox),
2885 gtk_vseparator_new(), FALSE, FALSE, 4);
2886 gtk_box_pack_start(GTK_BOX(hbox),
2887 btn_rename = gtk_button_new_with_label(_("Rename...")),
2889 gtk_box_pack_start(GTK_BOX(hbox),
2890 btn_delete = gtk_button_new_with_label(_("Delete...")),
2892 gtk_box_pack_start(GTK_BOX(hbox),
2893 btn_new = gtk_button_new_with_label(_("New...")),
2896 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2897 hbox, FALSE, FALSE, 4);
2899 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2900 gtk_hseparator_new(), TRUE, TRUE, 4);
2901 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2902 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
2904 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
2905 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
2907 rmi.repo_edits = NULL;
2909 /* Connect signals. */
2910 g_signal_connect(G_OBJECT(btn_rename), "clicked",
2911 G_CALLBACK(repoman_dialog_rename), &rmi);
2912 g_signal_connect(G_OBJECT(btn_delete), "clicked",
2913 G_CALLBACK(repoman_dialog_delete), &rmi);
2914 g_signal_connect(G_OBJECT(btn_new), "clicked",
2915 G_CALLBACK(repoman_dialog_new), &rmi);
2916 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
2917 G_CALLBACK(repoman_dialog_select), &rmi);
2920 /* Populate combo box and pages in notebook. */
2921 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
2923 RepoData *rd = (RepoData*)curr->data;
2924 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
2926 /* store this to be able to walk through layers attached to repo */
2929 /* Initialize fields with data from the RepoData object. */
2930 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2931 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
2933 hildon_controlbar_set_value(
2934 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2936 hildon_controlbar_set_value(
2937 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2938 rd->view_zoom_steps);
2939 gtk_toggle_button_set_active(
2940 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2942 gtk_toggle_button_set_active(
2943 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2945 hildon_number_editor_set_value(
2946 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2948 hildon_number_editor_set_value(
2949 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2951 if(rd == _curr_repo)
2952 curr_repo_index = i;
2955 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
2956 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
2958 gtk_widget_show_all(dialog);
2960 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2962 /* Iterate through repos and verify each. */
2963 gboolean verified = TRUE;
2966 gchar *old_curr_repo_name = _curr_repo->name;
2968 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2970 /* Check the ranges for the min and max zoom levels. */
2971 RepoEditInfo *rei = curr->data;
2972 if(hildon_number_editor_get_value(
2973 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
2974 < hildon_number_editor_get_value(
2975 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
2983 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
2985 _("Minimum Downloadable Zoom must be less than "
2986 "Maximum Downloadable Zoom."));
2990 /* We're good to replace. Remove old _repo_list menu items. */
2991 menu_maps_remove_repos();
2992 /* But keep the repo list in memory, in case downloads are using it. */
2995 /* Write new _repo_list. */
2996 curr_repo_index = gtk_combo_box_get_active(
2997 GTK_COMBO_BOX(rmi.cmb_repos));
2999 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
3001 RepoEditInfo *rei = curr->data;
3002 RepoData *rd = g_new0(RepoData, 1);
3003 RepoData *rd0, **rd1;
3004 rd->name = g_strdup(rei->name);
3005 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
3006 rd->db_filename = gnome_vfs_expand_initial_tilde(
3007 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
3008 rd->dl_zoom_steps = hildon_controlbar_get_value(
3009 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
3010 rd->view_zoom_steps = hildon_controlbar_get_value(
3011 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
3012 rd->double_size = gtk_toggle_button_get_active(
3013 GTK_TOGGLE_BUTTON(rei->chk_double_size));
3014 rd->nextable = gtk_toggle_button_get_active(
3015 GTK_TOGGLE_BUTTON(rei->chk_nextable));
3016 rd->min_zoom = hildon_number_editor_get_value(
3017 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
3018 rd->max_zoom = hildon_number_editor_get_value(
3019 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
3023 rd0 = rei->repo->layers;
3027 *rd1 = g_new0 (RepoData, 1);
3028 (*rd1)->name = rd0->name;
3029 (*rd1)->url = rd0->url;
3030 (*rd1)->db_filename = rd0->db_filename;
3031 (*rd1)->layer_enabled = rd0->layer_enabled;
3032 (*rd1)->layer_refresh_interval = rd0->layer_refresh_interval;
3033 (*rd1)->layer_refresh_countdown = rd0->layer_refresh_countdown;
3034 (*rd1)->layer_level = rd0->layer_level;
3036 (*rd1)->dl_zoom_steps = rd0->dl_zoom_steps;
3037 (*rd1)->view_zoom_steps = rd0->view_zoom_steps;
3038 (*rd1)->double_size = rd0->double_size;
3039 (*rd1)->nextable = rd0->nextable;
3040 (*rd1)->min_zoom = rd0->min_zoom;
3041 (*rd1)->max_zoom = rd0->max_zoom;
3043 set_repo_type (*rd1);
3046 rd1 = &(*rd1)->layers;
3053 rd->layer_level = 0;
3056 _repo_list = g_list_append(_repo_list, rd);
3058 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
3060 else if(i == curr_repo_index)
3064 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
3065 menu_maps_add_repos();
3071 gtk_widget_hide(dialog);
3073 /* Clear out the notebook entries. */
3074 while(rmi.repo_edits)
3075 repoman_delete(&rmi, 0);
3077 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
3078 map_refresh_mark (TRUE);
3080 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3085 mapman_by_area(gdouble start_lat, gdouble start_lon,
3086 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
3087 MapUpdateType update_type,
3088 gint download_batch_id)
3090 gint start_unitx, start_unity, end_unitx, end_unity;
3095 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
3098 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
3099 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
3101 /* Swap if they specified flipped lats or lons. */
3102 if(start_unitx > end_unitx)
3104 gint swap = start_unitx;
3105 start_unitx = end_unitx;
3108 if(start_unity > end_unity)
3110 gint swap = start_unity;
3111 start_unity = end_unity;
3115 /* First, get the number of maps to download. */
3116 for(z = 0; z <= MAX_ZOOM; ++z)
3118 if(gtk_toggle_button_get_active(
3119 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3121 gint start_tilex, start_tiley, end_tilex, end_tiley;
3122 start_tilex = unit2ztile(start_unitx, z);
3123 start_tiley = unit2ztile(start_unity, z);
3124 end_tilex = unit2ztile(end_unitx, z);
3125 end_tiley = unit2ztile(end_unity, z);
3126 num_maps += (end_tilex - start_tilex + 1)
3127 * (end_tiley - start_tiley + 1);
3131 if(update_type == MAP_UPDATE_DELETE)
3133 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
3134 num_maps, _("maps "));
3138 snprintf(buffer, sizeof(buffer),
3139 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
3140 num_maps, _("maps"), _("up to about"),
3141 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
3143 confirm = hildon_note_new_confirmation(
3144 GTK_WINDOW(mapman_info->dialog), buffer);
3146 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
3148 gtk_widget_destroy(confirm);
3149 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
3153 g_mutex_lock(_mut_priority_mutex);
3154 for(z = 0; z <= MAX_ZOOM; ++z)
3156 if(gtk_toggle_button_get_active(
3157 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3159 gint start_tilex, start_tiley, end_tilex, end_tiley;
3161 start_tilex = unit2ztile(start_unitx, z);
3162 start_tiley = unit2ztile(start_unity, z);
3163 end_tilex = unit2ztile(end_unitx, z);
3164 end_tiley = unit2ztile(end_unity, z);
3165 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
3167 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
3169 /* Make sure this tile is even possible. */
3170 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
3171 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
3173 RepoData* rd = _curr_repo;
3176 if (rd == _curr_repo || (rd->layer_enabled && rd->db))
3177 mapdb_initiate_update(rd, z, tilex, tiley,
3178 update_type, download_batch_id,
3179 (abs(tilex - unit2tile(_next_center.unitx))
3180 + abs(tiley - unit2tile(_next_center.unity))),
3189 g_mutex_unlock(_mut_priority_mutex);
3191 gtk_widget_destroy(confirm);
3192 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3197 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
3198 gint download_batch_id)
3201 gint prev_tilex, prev_tiley, num_maps = 0, z;
3204 gint radius = hildon_number_editor_get_value(
3205 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
3206 printf("%s()\n", __PRETTY_FUNCTION__);
3208 /* First, get the number of maps to download. */
3209 for(z = 0; z <= MAX_ZOOM; ++z)
3211 if(gtk_toggle_button_get_active(
3212 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3216 for(curr = _route.head - 1; curr++ != _route.tail; )
3220 gint tilex = unit2ztile(curr->unitx, z);
3221 gint tiley = unit2ztile(curr->unity, z);
3222 if(tilex != prev_tilex || tiley != prev_tiley)
3225 num_maps += (abs((gint)tilex - prev_tilex) + 1)
3226 * (abs((gint)tiley - prev_tiley) + 1) - 1;
3234 num_maps *= 0.625 * pow(radius + 1, 1.85);
3236 if(update_type == MAP_UPDATE_DELETE)
3238 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
3239 _("Confirm DELETION of"), _("about"),
3240 num_maps, _("maps "));
3244 snprintf(buffer, sizeof(buffer),
3245 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
3247 num_maps, _("maps"), _("up to about"),
3248 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
3250 confirm = hildon_note_new_confirmation(
3251 GTK_WINDOW(mapman_info->dialog), buffer);
3253 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
3255 gtk_widget_destroy(confirm);
3256 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
3260 /* Now, do the actual download. */
3261 g_mutex_lock(_mut_priority_mutex);
3262 for(z = 0; z <= MAX_ZOOM; ++z)
3264 if(gtk_toggle_button_get_active(
3265 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
3269 for(curr = _route.head - 1; curr++ != _route.tail; )
3273 gint tilex = unit2ztile(curr->unitx, z);
3274 gint tiley = unit2ztile(curr->unity, z);
3275 if(tilex != prev_tilex || tiley != prev_tiley)
3277 gint minx, miny, maxx, maxy, x, y;
3280 minx = MIN(tilex, prev_tilex) - radius;
3281 miny = MIN(tiley, prev_tiley) - radius;
3282 maxx = MAX(tilex, prev_tilex) + radius;
3283 maxy = MAX(tiley, prev_tiley) + radius;
3287 minx = tilex - radius;
3288 miny = tiley - radius;
3289 maxx = tilex + radius;
3290 maxy = tiley + radius;
3292 for(x = minx; x <= maxx; x++)
3294 for(y = miny; y <= maxy; y++)
3296 /* Make sure this tile is even possible. */
3298 < unit2ztile(WORLD_SIZE_UNITS, z)
3300 < unit2ztile(WORLD_SIZE_UNITS, z))
3302 mapdb_initiate_update(_curr_repo, z, x, y,
3303 update_type, download_batch_id,
3304 (abs(tilex - unit2tile(
3305 _next_center.unitx))
3306 + abs(tiley - unit2tile(
3307 _next_center.unity))),
3319 g_mutex_unlock(_mut_priority_mutex);
3320 _route_dl_radius = radius;
3321 gtk_widget_destroy(confirm);
3322 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3327 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
3330 printf("%s()\n", __PRETTY_FUNCTION__);
3331 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
3332 /* This is the second page (the "Zoom" page) - clear the checks. */
3333 for(z = 0; z <= MAX_ZOOM; ++z)
3334 gtk_toggle_button_set_active(
3335 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
3338 /* This is the first page (the "Area" page) - clear the text fields. */
3339 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
3340 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
3341 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
3342 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
3344 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3347 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
3349 printf("%s()\n", __PRETTY_FUNCTION__);
3350 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
3351 gtk_toggle_button_get_active(
3352 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
3354 if(gtk_toggle_button_get_active(
3355 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
3356 gtk_widget_show(mapman_info->tbl_area);
3357 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
3358 gtk_widget_hide(mapman_info->tbl_area);
3360 gtk_widget_set_sensitive(mapman_info->num_route_radius,
3361 gtk_toggle_button_get_active(
3362 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
3363 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3369 static GtkWidget *dialog = NULL;
3370 static GtkWidget *vbox = NULL;
3371 static GtkWidget *hbox = NULL;
3372 static GtkWidget *table = NULL;
3373 static GtkWidget *label = NULL;
3374 static GtkWidget *button = NULL;
3375 static GtkWidget *lbl_gps_lat = NULL;
3376 static GtkWidget *lbl_gps_lon = NULL;
3377 static GtkWidget *lbl_center_lat = NULL;
3378 static GtkWidget *lbl_center_lon = NULL;
3379 static MapmanInfo mapman_info;
3383 printf("%s()\n", __PRETTY_FUNCTION__);
3387 popup_error(_window, "To manage maps, you must set a valid repository "
3388 "database filename in the \"Manage Repositories\" dialog.");
3389 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3395 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
3397 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
3398 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
3401 /* Enable the help button. */
3403 hildon_help_dialog_help_enable(
3405 ossohelp_dialog_help_enable(
3407 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
3410 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
3411 button = gtk_button_new_with_label(_("Clear")));
3412 g_signal_connect(G_OBJECT(button), "clicked",
3413 G_CALLBACK(mapman_clear), &mapman_info);
3415 /* Cancel button. */
3416 gtk_dialog_add_button(GTK_DIALOG(dialog),
3417 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
3419 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
3420 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
3423 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3424 vbox = gtk_vbox_new(FALSE, 2),
3425 label = gtk_label_new(_("Setup")));
3426 gtk_notebook_set_tab_label_packing(
3427 GTK_NOTEBOOK(mapman_info.notebook), vbox,
3428 FALSE, FALSE, GTK_PACK_START);
3430 gtk_box_pack_start(GTK_BOX(vbox),
3431 hbox = gtk_hbox_new(FALSE, 4),
3433 gtk_box_pack_start(GTK_BOX(hbox),
3434 mapman_info.rad_download = gtk_radio_button_new_with_label(
3435 NULL,_("Download Maps")),
3437 gtk_box_pack_start(GTK_BOX(hbox),
3438 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
3440 gtk_container_add(GTK_CONTAINER(label),
3441 mapman_info.chk_overwrite
3442 = gtk_check_button_new_with_label(_("Overwrite"))),
3444 gtk_box_pack_start(GTK_BOX(vbox),
3445 mapman_info.rad_delete
3446 = gtk_radio_button_new_with_label_from_widget(
3447 GTK_RADIO_BUTTON(mapman_info.rad_download),
3451 gtk_box_pack_start(GTK_BOX(vbox),
3452 gtk_hseparator_new(),
3455 gtk_box_pack_start(GTK_BOX(vbox),
3456 mapman_info.rad_by_area
3457 = gtk_radio_button_new_with_label(NULL,
3458 _("By Area (see tab)")),
3460 gtk_box_pack_start(GTK_BOX(vbox),
3461 hbox = gtk_hbox_new(FALSE, 4),
3463 gtk_box_pack_start(GTK_BOX(hbox),
3464 mapman_info.rad_by_route
3465 = gtk_radio_button_new_with_label_from_widget(
3466 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
3467 _("Along Route - Radius (tiles):")),
3469 gtk_box_pack_start(GTK_BOX(hbox),
3470 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
3472 hildon_number_editor_set_value(
3473 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
3478 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3479 table = gtk_table_new(5, 5, FALSE),
3480 label = gtk_label_new(_("Zoom")));
3481 gtk_notebook_set_tab_label_packing(
3482 GTK_NOTEBOOK(mapman_info.notebook), table,
3483 FALSE, FALSE, GTK_PACK_START);
3484 gtk_table_attach(GTK_TABLE(table),
3485 label = gtk_label_new(
3486 _("Zoom Levels to Download: (0 = most detail)")),
3487 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
3488 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
3489 snprintf(buffer, sizeof(buffer), "%d", 0);
3490 gtk_table_attach(GTK_TABLE(table),
3491 mapman_info.chk_zoom_levels[0]
3492 = gtk_check_button_new_with_label(buffer),
3493 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
3494 for(z = 0; z < MAX_ZOOM; ++z)
3496 snprintf(buffer, sizeof(buffer), "%d", z + 1);
3497 gtk_table_attach(GTK_TABLE(table),
3498 mapman_info.chk_zoom_levels[z + 1]
3499 = gtk_check_button_new_with_label(buffer),
3500 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
3505 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
3506 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
3507 label = gtk_label_new(_("Area")));
3509 /* Label Columns. */
3510 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3511 label = gtk_label_new(_("Latitude")),
3512 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
3513 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3514 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3515 label = gtk_label_new(_("Longitude")),
3516 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
3517 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3520 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3521 label = gtk_label_new(_("GPS Location")),
3522 0, 1, 1, 2, GTK_FILL, 0, 4, 0);
3523 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3524 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3525 lbl_gps_lat = gtk_label_new(""),
3526 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
3527 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
3528 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
3529 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3530 lbl_gps_lon = gtk_label_new(""),
3531 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
3532 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
3533 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
3536 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3537 label = gtk_label_new(_("View Center")),
3538 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
3539 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3540 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3541 lbl_center_lat = gtk_label_new(""),
3542 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
3543 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
3544 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
3545 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3546 lbl_center_lon = gtk_label_new(""),
3547 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
3548 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
3549 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
3551 /* default values for Top Left and Bottom Right are defined by the
3552 * rectangle of the current and the previous Center */
3555 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3556 label = gtk_label_new(_("Top-Left")),
3557 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
3558 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3559 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3560 mapman_info.txt_topleft_lat = gtk_entry_new(),
3561 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
3562 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
3563 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
3564 #ifdef MAEMO_CHANGES
3565 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
3567 "hildon-input-mode",
3568 HILDON_GTK_INPUT_MODE_FULL, NULL);
3570 HILDON_INPUT_MODE_HINT,
3571 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3572 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
3577 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3578 mapman_info.txt_topleft_lon = gtk_entry_new(),
3579 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
3580 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
3581 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
3582 #ifdef MAEMO_CHANGES
3583 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
3585 "hildon-input-mode",
3586 HILDON_GTK_INPUT_MODE_FULL, NULL);
3588 HILDON_INPUT_MODE_HINT,
3589 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3590 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
3597 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3598 label = gtk_label_new(_("Bottom-Right")),
3599 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
3600 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
3601 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3602 mapman_info.txt_botright_lat = gtk_entry_new(),
3603 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
3604 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
3605 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
3606 #ifdef MAEMO_CHANGES
3607 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
3609 "hildon-input-mode",
3610 HILDON_GTK_INPUT_MODE_FULL, NULL);
3612 HILDON_INPUT_MODE_HINT,
3613 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3614 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
3619 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
3620 mapman_info.txt_botright_lon = gtk_entry_new(),
3621 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
3622 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
3623 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
3624 #ifdef MAEMO_CHANGES
3625 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
3627 "hildon-input-mode",
3628 HILDON_GTK_INPUT_MODE_FULL, NULL);
3630 HILDON_INPUT_MODE_HINT,
3631 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
3632 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
3638 /* Default action is to download by area. */
3639 gtk_toggle_button_set_active(
3640 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
3642 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
3643 G_CALLBACK(mapman_update_state), &mapman_info);
3644 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
3645 G_CALLBACK(mapman_update_state), &mapman_info);
3646 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
3647 G_CALLBACK(mapman_update_state), &mapman_info);
3648 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
3649 G_CALLBACK(mapman_update_state), &mapman_info);
3652 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
3653 * output (and parsed) as locale-dependent. */
3655 gtk_widget_set_sensitive(mapman_info.rad_by_route,
3656 _route.head != _route.tail);
3658 lat_format(_gps.lat, buffer);
3659 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
3660 lon_format(_gps.lon, buffer);
3661 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
3663 unit2latlon(_center.unitx, _center.unity, lat, lon);
3664 lat_format(lat, buffer);
3665 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
3666 lon_format(lon, buffer);
3667 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
3669 /* Initialize to the bounds of the screen. */
3671 _center.unitx - pixel2unit(MAX(_view_width_pixels,
3672 _view_height_pixels) / 2),
3673 _center.unity - pixel2unit(MAX(_view_width_pixels,
3674 _view_height_pixels) / 2), lat, lon);
3675 BOUND(lat, -90.f, 90.f);
3676 BOUND(lon, -180.f, 180.f);
3677 lat_format(lat, buffer);
3678 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
3679 lon_format(lon, buffer);
3680 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
3683 _center.unitx + pixel2unit(MAX(_view_width_pixels,
3684 _view_height_pixels) / 2),
3685 _center.unity + pixel2unit(MAX(_view_width_pixels,
3686 _view_height_pixels) / 2), lat, lon);
3687 BOUND(lat, -90.f, 90.f);
3688 BOUND(lon, -180.f, 180.f);
3689 lat_format(lat, buffer);
3690 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
3691 lon_format(lon, buffer);
3692 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
3694 /* Initialize zoom levels. */
3697 for(i = 0; i <= MAX_ZOOM; i++)
3699 gtk_toggle_button_set_active(
3700 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
3703 gtk_toggle_button_set_active(
3704 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
3705 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
3707 gtk_widget_show_all(dialog);
3709 mapman_update_state(NULL, &mapman_info);
3711 if(_curr_repo->type != REPOTYPE_NONE)
3713 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
3717 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
3719 _("NOTE: You must set a Map URI in the current repository in "
3720 "order to download maps."));
3723 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
3725 MapUpdateType update_type;
3726 static gint8 download_batch_id = INT8_MIN;
3728 if(gtk_toggle_button_get_active(
3729 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
3730 update_type = MAP_UPDATE_DELETE;
3731 else if(gtk_toggle_button_get_active(
3732 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
3733 update_type = MAP_UPDATE_OVERWRITE;
3735 update_type = MAP_UPDATE_ADD;
3737 ++download_batch_id;
3738 if(gtk_toggle_button_get_active(
3739 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
3741 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
3748 gdouble start_lat, start_lon, end_lat, end_lon;
3750 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
3751 start_lat = strdmstod(text, &error_check);
3752 if(text == error_check || start_lat < -90. || start_lat > 90.) {
3753 popup_error(dialog, _("Invalid Top-Left Latitude"));
3757 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
3758 start_lon = strdmstod(text, &error_check);
3759 if(text == error_check || start_lon < -180. || start_lon>180.) {
3760 popup_error(dialog, _("Invalid Top-Left Longitude"));
3764 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
3765 end_lat = strdmstod(text, &error_check);
3766 if(text == error_check || end_lat < -90. || end_lat > 90.) {
3767 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
3771 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
3772 end_lon = strdmstod(text, &error_check);
3773 if(text == error_check || end_lon < -180. || end_lon > 180.) {
3774 popup_error(dialog,_("Invalid Bottom-Right Longitude"));
3778 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
3779 &mapman_info, update_type, download_batch_id))
3784 gtk_widget_hide(dialog);
3786 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3791 /* changes visibility of current repo's layers to it's previous state */
3792 void maps_toggle_visible_layers ()
3794 RepoData *rd = _curr_repo;
3795 gboolean changed = FALSE;
3797 printf("%s()\n", __PRETTY_FUNCTION__);
3800 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3807 if (rd->layer_enabled) {
3809 rd->layer_was_enabled = rd->layer_enabled;
3810 rd->layer_enabled = FALSE;
3813 rd->layer_enabled = rd->layer_was_enabled;
3814 if (rd->layer_was_enabled)
3823 menu_layers_remove_repos ();
3824 menu_layers_add_repos ();
3826 map_refresh_mark (TRUE);
3829 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3834 /* this routine fired by timer every minute and decrements refetch counter of every active layer of
3835 current repository. If one of layer is expired, it forces map redraw. Redraw routine checks every
3836 layer's tile download timestamp and desides performs refetch if needed */
3838 map_layer_refresh_cb (gpointer data)
3840 RepoData* rd = _curr_repo;
3841 gboolean refresh = FALSE;
3842 printf("%s()\n", __PRETTY_FUNCTION__);
3848 if (rd->layer_enabled && rd->layer_refresh_interval) {
3849 rd->layer_refresh_countdown--;
3850 if (rd->layer_refresh_countdown <= 0) {
3851 rd->layer_refresh_countdown = rd->layer_refresh_interval;
3861 map_refresh_mark (TRUE);
3863 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3870 Returns amount of seconds since tile downloaded or 0 if tile
3871 have no such information.
3873 gint get_tile_age (GdkPixbuf* pixbuf)
3878 ts = gdk_pixbuf_get_option (pixbuf, layer_timestamp_key);
3883 if (sscanf (ts, "%u", &val))
3884 return time (NULL) - val;