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>
38 # include <hildon/hildon-help.h>
39 # include <hildon/hildon-note.h>
40 # include <hildon/hildon-file-chooser-dialog.h>
41 # include <hildon/hildon-number-editor.h>
42 # include <hildon/hildon-banner.h>
44 # include <osso-helplib.h>
45 # include <hildon-widgets/hildon-note.h>
46 # include <hildon-widgets/hildon-file-chooser-dialog.h>
47 # include <hildon-widgets/hildon-number-editor.h>
48 # include <hildon-widgets/hildon-banner.h>
49 # include <hildon-widgets/hildon-input-mode-hint.h>
65 typedef struct _RepoManInfo RepoManInfo;
73 typedef struct _RepoEditInfo RepoEditInfo;
74 struct _RepoEditInfo {
77 GtkWidget *txt_db_filename;
78 GtkWidget *num_dl_zoom_steps;
79 GtkWidget *num_view_zoom_steps;
80 GtkWidget *chk_double_size;
81 GtkWidget *chk_nextable;
82 GtkWidget *btn_browse;
83 GtkWidget *btn_compact;
84 GtkWidget *num_min_zoom;
85 GtkWidget *num_max_zoom;
86 BrowseInfo browse_info;
89 typedef struct _MapmanInfo MapmanInfo;
95 /* The "Setup" tab. */
96 GtkWidget *rad_download;
97 GtkWidget *rad_delete;
98 GtkWidget *chk_overwrite;
99 GtkWidget *rad_by_area;
100 GtkWidget *rad_by_route;
101 GtkWidget *num_route_radius;
103 /* The "Area" tab. */
104 GtkWidget *txt_topleft_lat;
105 GtkWidget *txt_topleft_lon;
106 GtkWidget *txt_botright_lat;
107 GtkWidget *txt_botright_lon;
109 /* The "Zoom" tab. */
110 GtkWidget *chk_zoom_levels[MAX_ZOOM + 1];
113 typedef struct _CompactInfo CompactInfo;
114 struct _CompactInfo {
118 const gchar *db_filename;
122 typedef struct _MapCacheKey MapCacheKey;
123 struct _MapCacheKey {
130 typedef struct _MapCacheEntry MapCacheEntry;
131 struct _MapCacheEntry {
142 typedef struct _MapCacheList MapCacheList;
143 struct _MapCacheList {
150 typedef struct _MapCache MapCache;
152 MapCacheList lists[4];
161 static MapCache _map_cache;
165 mapdb_get_data(RepoData *repo, gint zoom, gint tilex, gint tiley, gchar **data)
168 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
169 repo->name, zoom, tilex, tiley);
175 /* There is no cache. Return NULL. */
176 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__,size);
181 /* Attempt to retrieve map from database. */
182 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
183 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
184 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
185 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select))
187 const gchar *bytes = NULL;
188 size = sqlite3_column_bytes(repo->stmt_map_select, 0);
190 /* "Pixbufs" of size less than or equal to MAX_PIXBUF_DUP_SIZE are
191 * actually keys into the dups table. */
192 if(size <= MAX_PIXBUF_DUP_SIZE)
194 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
195 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_select, 1, hash)
196 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_select))
198 bytes = sqlite3_column_blob(repo->stmt_dup_select, 0);
199 size = sqlite3_column_bytes(repo->stmt_dup_select, 0);
203 /* Not there? Delete the entry, then. */
204 if(SQLITE_OK != sqlite3_bind_int(
205 repo->stmt_map_delete, 1, zoom)
206 || SQLITE_OK != sqlite3_bind_int(
207 repo->stmt_map_delete, 2, tilex)
208 || SQLITE_OK != sqlite3_bind_int(
209 repo->stmt_map_delete, 3, tiley)
210 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
212 printf("Error in stmt_map_delete: %s\n",
213 sqlite3_errmsg(repo->db));
215 sqlite3_reset(repo->stmt_map_delete);
217 /* We have no bytes to return to the caller. */
221 /* Don't reset the statement yet - we need the blob. */
225 bytes = sqlite3_column_blob(repo->stmt_map_select, 0);
229 *data = g_slice_alloc(size);
230 memcpy(*data, bytes, size);
232 if(size <= MAX_PIXBUF_DUP_SIZE)
233 sqlite3_reset(repo->stmt_dup_select);
235 sqlite3_reset(repo->stmt_map_select);
244 d.dptr = (gchar*)&key;
245 d.dsize = sizeof(key);
246 d = gdbm_fetch(repo->db, d);
250 *data = g_slice_alloc(size);
251 memcpy(*data, d.dptr, size);
257 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__, size);
261 static void map_cache_list_remove(MapCacheList *_list, MapCacheEntry *_entry)
263 _list->size -= _entry->size;
264 _list->data_sz -= _entry->data_sz;
265 *(_entry->prev != NULL?&_entry->prev->next:&_list->head) = _entry->next;
266 *(_entry->next != NULL?&_entry->next->prev:&_list->tail) = _entry->prev;
269 static void map_cache_list_prepend(MapCacheList *_list, int _li,
270 MapCacheEntry *_entry)
273 _entry->next = _list[_li].head;
274 *(_list[_li].head != NULL?&_list[_li].head->prev:&_list[_li].tail) = _entry;
275 _list[_li].head = _entry;
276 _list[_li].size += _entry->size;
277 _list[_li].data_sz += _entry->data_sz;
281 static guint map_cache_key_hash(gconstpointer _key){
282 const MapCacheKey *key;
283 key = (const MapCacheKey *)_key;
284 return g_direct_hash(key->repo)+g_int_hash(&key->zoom)+
285 g_int_hash(&key->tilex)+g_int_hash(&key->tiley);
288 static gboolean map_cache_key_equal(gconstpointer _v1, gconstpointer _v2){
289 const MapCacheKey *key1;
290 const MapCacheKey *key2;
291 key1 = (const MapCacheKey *)_v1;
292 key2 = (const MapCacheKey *)_v2;
293 return key1->tilex == key2->tilex && key1->tiley == key2->tiley &&
294 key1->zoom == key2->zoom && key1->repo == key2->repo;
297 static void map_cache_entry_make_pixbuf(MapCacheEntry *_entry){
298 if (_entry->data != NULL)
301 GdkPixbufLoader *loader;
303 loader = gdk_pixbuf_loader_new();
304 gdk_pixbuf_loader_write(loader, _entry->data, _entry->data_sz, NULL);
305 gdk_pixbuf_loader_close(loader, &error);
308 _entry->pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
309 _entry->size = _entry->data_sz+
310 gdk_pixbuf_get_rowstride(_entry->pixbuf)*
311 gdk_pixbuf_get_height(_entry->pixbuf);
312 g_object_unref(loader);
315 g_object_unref(loader);
316 g_slice_free1(_entry->data_sz, _entry->data);
320 _entry->pixbuf = NULL;
321 _entry->size = _entry->data_sz;
324 static void map_cache_entry_free_pixbuf(MapCacheEntry *_entry){
325 if(_entry->pixbuf!=NULL)
327 g_object_unref(_entry->pixbuf);
328 _entry->pixbuf = NULL;
332 static void map_cache_entry_free(MapCacheEntry *_entry){
333 if(_entry->list >= 0)
334 map_cache_list_remove(_map_cache.lists+_entry->list, _entry);
335 map_cache_entry_free_pixbuf(_entry);
336 g_slice_free1(_entry->data_sz, _entry->data);
337 g_slice_free(MapCacheEntry, _entry);
341 map_cache_replace(size_t _size, gboolean _b2)
345 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
346 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
348 while(total_size+_size > _map_cache.cache_size)
350 MapCacheEntry *entry;
352 if(_map_cache.lists[0].tail != NULL &&
353 (_map_cache.lists[0].size > _map_cache.p ||
354 (_b2 && _map_cache.lists[0].size == _map_cache.p)))
358 entry = _map_cache.lists[list].tail;
361 map_cache_list_remove(_map_cache.lists+list, entry);
362 map_cache_list_prepend(_map_cache.lists, list+1, entry);
363 total_size -= entry->size - entry->data_sz;
371 map_cache_evict(size_t _size)
375 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
376 +_map_cache.lists[2].size+_map_cache.lists[3].size;
377 max_size = _map_cache.cache_size<<1;
380 if(_map_cache.lists[0].size+_map_cache.lists[1].size+_size >
381 _map_cache.cache_size)
383 if(_map_cache.lists[1].tail != NULL)
385 g_hash_table_remove(_map_cache.entries,
386 &_map_cache.lists[1].tail->key);
387 map_cache_replace(_size, FALSE);
389 else if(_map_cache.lists[0].tail != NULL)
391 g_hash_table_remove(_map_cache.entries,
392 &_map_cache.lists[0].tail->key);
396 else if(total_size+_size > _map_cache.cache_size)
398 if(total_size+_size > max_size &&
399 _map_cache.lists[3].tail != NULL)
401 g_hash_table_remove(_map_cache.entries,
402 &_map_cache.lists[3].tail->key);
403 map_cache_replace(_size, FALSE);
405 else if(!map_cache_replace(_size, FALSE))
409 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
410 +_map_cache.lists[2].size+_map_cache.lists[3].size;
415 map_cache_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
418 MapCacheEntry *entry;
423 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
426 map_cache_list_remove(_map_cache.lists+entry->list, entry);
427 if(entry->pixbuf == NULL)
431 map_cache_entry_make_pixbuf(entry);
432 bsize = _map_cache.lists[entry->list].size+entry->size;
435 dp = _map_cache.lists[entry->list^2].size/bsize;
441 if(_map_cache.p > _map_cache.cache_size)
442 _map_cache.p = _map_cache.cache_size;
443 map_cache_replace(entry->size, FALSE);
447 if(dp > _map_cache.p)
451 map_cache_replace(entry->size, TRUE);
457 map_cache_list_prepend(_map_cache.lists, 2, entry);
463 data_sz = mapdb_get_data(repo, zoom, tilex, tiley, &data);
464 entry = g_slice_new(MapCacheEntry);
465 *&entry->key = *&key;
467 entry->data_sz = data_sz;
468 map_cache_entry_make_pixbuf(entry);
469 map_cache_evict(entry->size);
470 map_cache_list_prepend(_map_cache.lists, 0, entry);
471 g_hash_table_insert(_map_cache.entries, &entry->key, entry);
474 if(entry->pixbuf != NULL)
475 g_object_ref(entry->pixbuf);
476 return entry->pixbuf;
480 map_cache_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
481 gchar *data,guint size)
484 MapCacheEntry *entry;
489 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
492 g_slice_free1(entry->data_sz, entry->data);
493 entry->data = g_slice_alloc(size);
494 memcpy(entry->data, data, size);
495 entry->data_sz = size;
496 if(entry->pixbuf != NULL)
498 map_cache_entry_free_pixbuf(entry);
499 map_cache_list_remove(_map_cache.lists+entry->list, entry);
500 map_cache_list_prepend(_map_cache.lists, entry->list+1, entry);
506 map_cache_remove(RepoData *repo, gint zoom, gint tilex, gint tiley)
513 g_hash_table_remove(_map_cache.entries, &key);
517 map_cache_init(size_t cache_size)
519 g_mutex_lock(_mapdb_mutex);
520 if(_map_cache.entries == NULL)
521 _map_cache.entries = g_hash_table_new_full(map_cache_key_hash,
522 map_cache_key_equal, NULL, (GDestroyNotify)map_cache_entry_free);
523 _map_cache.cache_size = cache_size;
524 if(_map_cache.p > cache_size)
525 _map_cache.p = cache_size;
527 g_mutex_unlock(_mapdb_mutex);
531 map_cache_resize(size_t cache_size)
534 g_mutex_lock(_mapdb_mutex);
535 _map_cache.cache_size = cache_size;
536 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
537 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
538 g_mutex_unlock(_mapdb_mutex);
543 map_cache_destroy(void)
545 g_mutex_lock(_mapdb_mutex);
546 if(_map_cache.entries != NULL)
548 g_hash_table_destroy(_map_cache.entries);
549 _map_cache.entries = NULL;
550 printf("thits: %u (%0.2f%%) bhits: %u (%0.2f%%) "
551 "misses: %u (%0.2f%%)\n",
552 _map_cache.thits, 100*_map_cache.thits/(double)(
553 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
554 _map_cache.bhits, 100*_map_cache.bhits/(double)(
555 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
556 _map_cache.misses, 100*_map_cache.misses/(double)(
557 _map_cache.thits+_map_cache.bhits+_map_cache.misses));
559 g_mutex_unlock(_mapdb_mutex);
563 mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley)
566 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
567 repo->name, zoom, tilex, tiley);
569 g_mutex_lock(_mapdb_mutex);
573 /* There is no cache. Return FALSE. */
574 g_mutex_unlock(_mapdb_mutex);
575 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
579 /* Search the cache first. */
582 MapCacheEntry *entry;
587 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
591 ret = entry->data != NULL;
592 g_mutex_unlock(_mapdb_mutex);
598 /* Attempt to retrieve map from database. */
599 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom)
600 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex)
601 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley)
602 && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists)
603 && sqlite3_column_int(repo->stmt_map_exists, 0) > 0)
611 sqlite3_reset(repo->stmt_map_exists);
620 d.dptr = (gchar*)&key;
621 d.dsize = sizeof(key);
622 exists = gdbm_exists(repo->db, d);
626 g_mutex_unlock(_mapdb_mutex);
628 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists);
633 mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
636 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
637 repo->name, zoom, tilex, tiley);
638 g_mutex_lock(_mapdb_mutex);
639 pixbuf = map_cache_get(repo, zoom, tilex, tiley);
640 g_mutex_unlock(_mapdb_mutex);
641 vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf);
647 mapdb_checkdec(RepoData *repo, gint zoom, gint tilex, gint tiley)
649 gboolean success = TRUE;
650 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
651 repo->name, zoom, tilex, tiley);
653 /* First, we have to check if the old map was a dup. */
654 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
655 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
656 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
657 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)
658 && sqlite3_column_bytes(repo->stmt_map_select, 0)
659 <= MAX_PIXBUF_DUP_SIZE)
661 /* Old map was indeed a dup. Decrement the reference count. */
662 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
663 if(SQLITE_OK != sqlite3_bind_int(
664 repo->stmt_dup_decrem, 1, hash)
665 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_decrem)
666 || SQLITE_OK != sqlite3_bind_int(
667 repo->stmt_dup_delete, 1, hash)
668 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_delete))
671 printf("Error in stmt_dup_decrem: %s\n",
672 sqlite3_errmsg(repo->db));
674 sqlite3_reset(repo->stmt_dup_delete);
675 sqlite3_reset(repo->stmt_dup_decrem);
677 sqlite3_reset(repo->stmt_map_select);
679 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
685 mapdb_update(gboolean exists, RepoData *repo,
686 gint zoom, gint tilex, gint tiley, void *bytes, gint size)
693 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
694 repo->name, zoom, tilex, tiley);
696 g_mutex_lock(_mapdb_mutex);
697 map_cache_update(repo, zoom, tilex, tiley, bytes, size);
701 /* There is no cache. Return FALSE. */
702 g_mutex_unlock(_mapdb_mutex);
703 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
708 /* At least try to open a transaction. */
709 sqlite3_step(repo->stmt_trans_begin);
710 sqlite3_reset(repo->stmt_trans_begin);
712 /* Pixbufs of size MAX_PIXBUF_DUP_SIZE or less are special. They are
713 * probably PNGs of a single color (like blue for water or beige for empty
714 * land). To reduce redundancy in the database, we will store them in a
715 * separate table and, in the maps table, only refer to them. */
716 if(size <= MAX_PIXBUF_DUP_SIZE)
718 /* Duplicate pixbuf. */
721 /* First, check if we need to remove a count from the dups table.*/
722 mapdb_checkdec(repo, zoom, tilex, tiley);
726 /* Compute hash of the bytes. */
727 gchar *cur = bytes, *end = bytes + size;
730 hash = (hash << 5) - hash + *(++cur);
732 /* Check if dup already exists. */
733 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_exists, 1, hash)
734 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_exists)
735 && sqlite3_column_int(repo->stmt_dup_exists, 0) > 0)
737 /* Dup already exists - increment existing entry. */
738 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_increm,1, hash)
739 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_increm))
742 printf("Error in stmt_dup_increm: %s\n",
743 sqlite3_errmsg(repo->db));
745 sqlite3_reset(repo->stmt_dup_increm);
749 /* Dup doesn't exist - add new entry. */
750 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_insert,1, hash)
751 || SQLITE_OK != sqlite3_bind_blob(repo->stmt_dup_insert,
752 2, bytes, size, NULL)
753 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_insert))
756 printf("Error in stmt_dup_insert: %s\n",
757 sqlite3_errmsg(repo->db));
759 sqlite3_reset(repo->stmt_dup_insert);
761 sqlite3_reset(repo->stmt_dup_exists);
763 /* Now, if successful so far, we fall through the end of this if
764 * statement and insert the hash as the blob. Setting bytes to NULL
765 * is the signal to do this. */
771 stmt = exists ? repo->stmt_map_update : repo->stmt_map_insert;
773 /* Attempt to insert map from database. */
774 if(SQLITE_OK != (bytes ? sqlite3_bind_blob(stmt, 1, bytes, size, NULL)
775 : sqlite3_bind_int(stmt, 1, hash))
776 || SQLITE_OK != sqlite3_bind_int(stmt, 2, zoom)
777 || SQLITE_OK != sqlite3_bind_int(stmt, 3, tilex)
778 || SQLITE_OK != sqlite3_bind_int(stmt, 4, tiley)
779 || SQLITE_DONE != sqlite3_step(stmt))
782 printf("Error in mapdb_update: %s\n", sqlite3_errmsg(repo->db));
789 sqlite3_step(repo->stmt_trans_commit);
790 sqlite3_reset(repo->stmt_trans_commit);
794 sqlite3_step(repo->stmt_trans_rollback);
795 sqlite3_reset(repo->stmt_trans_rollback);
806 dkey.dptr = (gchar*)&key;
807 dkey.dsize = sizeof(key);
810 success = !gdbm_store(repo->db, dkey, dcon, GDBM_REPLACE);
813 g_mutex_unlock(_mapdb_mutex);
815 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
820 mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley)
822 gint success = FALSE;
823 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
824 repo->name, zoom, tilex, tiley);
826 g_mutex_lock(_mapdb_mutex);
827 map_cache_remove(repo, zoom, tilex, tiley);
831 /* There is no cache. Return FALSE. */
832 g_mutex_unlock(_mapdb_mutex);
833 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
838 /* At least try to open a transaction. */
839 sqlite3_step(repo->stmt_trans_begin);
840 sqlite3_reset(repo->stmt_trans_begin);
842 /* First, check if we need to remove a count from the dups table. */
843 /* Then, attempt to delete map from database. */
844 if(!mapdb_checkdec(repo, zoom, tilex, tiley)
845 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 1, zoom)
846 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 2, tilex)
847 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 3, tiley)
848 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
851 printf("Error in stmt_map_delete: %s\n",
852 sqlite3_errmsg(repo->db));
854 sqlite3_reset(repo->stmt_map_delete);
858 sqlite3_step(repo->stmt_trans_commit);
859 sqlite3_reset(repo->stmt_trans_commit);
863 sqlite3_step(repo->stmt_trans_rollback);
864 sqlite3_reset(repo->stmt_trans_rollback);
874 d.dptr = (gchar*)&key;
875 d.dsize = sizeof(key);
876 success = !gdbm_delete(repo->db, d);
879 g_mutex_unlock(_mapdb_mutex);
881 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
886 set_repo_type(RepoData *repo)
888 printf("%s(%s)\n", __PRETTY_FUNCTION__, repo->url);
890 if(repo->url && *repo->url)
892 gchar *url = g_utf8_strdown(repo->url, -1);
894 /* Determine type of repository. */
895 if(strstr(url, "service=wms"))
896 repo->type = REPOTYPE_WMS;
897 else if(strstr(url, "%s"))
898 repo->type = REPOTYPE_QUAD_QRST;
899 else if(strstr(url, "%0d"))
900 repo->type = REPOTYPE_XYZ_INV;
901 else if(strstr(url, "%-d"))
902 repo->type = REPOTYPE_XYZ_SIGNED;
903 else if(strstr(url, "%0s"))
904 repo->type = REPOTYPE_QUAD_ZERO;
906 repo->type = REPOTYPE_XYZ;
911 repo->type = REPOTYPE_NONE;
913 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
916 /* Returns the directory containing the given database filename, or NULL
917 * if the database file could not be created. */
919 repo_make_db(RepoData *rd)
921 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
925 db_dirname = g_path_get_dirname(rd->db_filename);
927 /* Check if db_filename is a directory and ask to upgrade. */
928 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
930 gchar buffer[BUFFER_SIZE];
931 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
932 g_free(rd->db_filename);
933 rd->db_filename = new_name;
935 snprintf(buffer, sizeof(buffer), "%s",
936 _("The current repository is in a legacy format and will "
937 "be converted. You should delete your old maps if you "
938 "no longer plan to use them."));
939 popup_error(_window, buffer);
942 if(g_mkdir_with_parents(db_dirname, 0755))
949 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
951 fd = g_creat(rd->db_filename, 0644);
960 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
961 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
962 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
966 repo_set_curr(RepoData *rd)
968 printf("%s()\n", __PRETTY_FUNCTION__);
969 if(!rd->db_filename || !*rd->db_filename
976 g_mutex_lock(_mapdb_mutex);
978 sqlite3_close(_curr_repo->db);
980 gdbm_close(_curr_repo->db);
982 _curr_repo->db = NULL;
983 g_mutex_unlock(_mapdb_mutex);
987 /* Set the current repository! */
990 /* Set up the database. */
991 if(_curr_repo->db_filename && *_curr_repo->db_filename)
995 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
997 /* Open worked. Now create tables, failing if they already exist.*/
998 || (sqlite3_exec(_curr_repo->db,
999 "create table maps ("
1004 "primary key (zoom, tilex, tiley))"
1006 "create table dups ("
1007 "hash integer primary key, "
1010 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
1011 /* Prepare select map statement. */
1012 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1013 "select pixbuf from maps "
1014 "where zoom = ? and tilex = ? and tiley = ?",
1015 -1, &_curr_repo->stmt_map_select, NULL)
1016 /* Prepare exists map statement. */
1017 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1018 "select count(*) from maps "
1019 "where zoom = ? and tilex = ? and tiley = ?",
1020 -1, &_curr_repo->stmt_map_exists, NULL)
1021 /* Prepare insert map statement. */
1022 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1023 "insert into maps (pixbuf, zoom, tilex, tiley)"
1024 " values (?, ?, ?, ?)",
1025 -1, &_curr_repo->stmt_map_insert, NULL)
1026 /* Prepare update map statement. */
1027 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1028 "update maps set pixbuf = ? "
1029 "where zoom = ? and tilex = ? and tiley = ?",
1030 -1, &_curr_repo->stmt_map_update, NULL)
1031 /* Prepare delete map statement. */
1032 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1034 "where zoom = ? and tilex = ? and tiley = ?",
1035 -1, &_curr_repo->stmt_map_delete, NULL)
1037 /* Prepare select-by-map dup statement. */
1038 /* Prepare select-by-hash dup statement. */
1039 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1040 "select pixbuf from dups "
1042 -1, &_curr_repo->stmt_dup_select, NULL)
1043 /* Prepare exists map statement. */
1044 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1045 "select count(*) from dups "
1047 -1, &_curr_repo->stmt_dup_exists, NULL)
1048 /* Prepare insert dup statement. */
1049 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1050 "insert into dups (hash, pixbuf, uses) "
1052 -1, &_curr_repo->stmt_dup_insert, NULL)
1053 /* Prepare increment dup statement. */
1054 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1056 "set uses = uses + 1 "
1058 -1, &_curr_repo->stmt_dup_increm, NULL)
1059 /* Prepare decrement dup statement. */
1060 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1062 "set uses = uses - 1 "
1064 -1, &_curr_repo->stmt_dup_decrem, NULL)
1065 /* Prepare delete dup statement. */
1066 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1068 "where hash = ? and uses <= 0",
1069 -1, &_curr_repo->stmt_dup_delete, NULL)
1071 /* Prepare begin-transaction statement. */
1072 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1073 "begin transaction",
1074 -1, &_curr_repo->stmt_trans_begin, NULL)
1075 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1076 "commit transaction",
1077 -1, &_curr_repo->stmt_trans_commit, NULL)
1078 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1079 "rollback transaction", -1,
1080 &_curr_repo->stmt_trans_rollback, NULL))
1082 gchar buffer[BUFFER_SIZE];
1083 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
1084 _("Failed to open map database for repository"),
1085 sqlite3_errmsg(_curr_repo->db),
1086 _("Downloaded maps will not be cached."));
1087 sqlite3_close(_curr_repo->db);
1088 _curr_repo->db = NULL;
1089 popup_error(_window, buffer);
1092 _curr_repo->db = gdbm_open(_curr_repo->db_filename,
1093 0, GDBM_WRCREAT | GDBM_FAST, 0644, NULL);
1096 gchar buffer[BUFFER_SIZE];
1097 snprintf(buffer, sizeof(buffer), "%s\n%s",
1098 _("Failed to open map database for repository"),
1099 _("Downloaded maps will not be cached."));
1100 _curr_repo->db = NULL;
1101 popup_error(_window, buffer);
1107 _curr_repo->db = NULL;
1109 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1114 gchar buffer[BUFFER_SIZE];
1115 snprintf(buffer, sizeof(buffer), "%s: %s",
1116 _("Unable to create map database for repository"), rd->name);
1117 popup_error(_window, buffer);
1119 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1125 * Given a wms uri pattern, compute the coordinate transformation and
1127 * 'proj' is used for the conversion
1130 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
1132 gint system_retcode;
1133 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
1136 gdouble lon1, lat1, lon2, lat2;
1138 gchar *widthstr = strcasestr(uri,"WIDTH=");
1139 gchar *heightstr = strcasestr(uri,"HEIGHT=");
1140 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
1141 gchar *srsstre = strchr(srsstr,'&');
1142 vprintf("%s()\n", __PRETTY_FUNCTION__);
1144 /* missing: test if found */
1146 strncpy(srs+4,srsstr+8,256);
1147 /* missing: test srsstre-srsstr < 526 */
1148 srs[srsstre-srsstr-4] = 0;
1149 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
1151 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
1152 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
1154 unit2latlon(tile2zunit(tilex,zoomlevel)
1155 - pixel2zunit(dwidth/2,zoomlevel),
1156 tile2zunit(tiley+1,zoomlevel)
1157 + pixel2zunit((dheight+1)/2,zoomlevel),
1160 unit2latlon(tile2zunit(tilex+1,zoomlevel)
1161 + pixel2zunit((dwidth+1)/2,zoomlevel),
1162 tile2zunit(tiley,zoomlevel)
1163 - pixel2zunit(dheight/2,zoomlevel),
1166 setlocale(LC_NUMERIC, "C");
1168 snprintf(cmd, sizeof(cmd),
1169 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
1170 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
1171 " > /tmp/tmpcs2cs ",
1172 lon1, lat1, lon2, lat2, srs);
1173 vprintf("Running command: %s\n", cmd);
1174 system_retcode = system(cmd);
1177 g_printerr("cs2cs returned error code %d\n",
1178 WEXITSTATUS(system_retcode));
1179 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
1180 g_printerr("Cannot open results of conversion\n");
1181 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
1182 &lon1, &lat1, cmd, &lon2, &lat2))
1184 g_printerr("Wrong conversion\n");
1190 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
1193 setlocale(LC_NUMERIC, "");
1195 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
1201 * Given the xyz coordinates of our map coordinate system, write the qrst
1202 * quadtree coordinates to buffer.
1205 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
1206 gchar *buffer, const gchar initial,
1207 const gchar *const quadrant)
1209 gchar *ptr = buffer;
1211 vprintf("%s()\n", __PRETTY_FUNCTION__);
1216 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
1218 gint xbit = (x >> n) & 1;
1219 gint ybit = (y >> n) & 1;
1220 *ptr++ = quadrant[xbit + 2 * ybit];
1223 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1227 * Construct the URL that we should fetch, based on the current URI format.
1228 * This method works differently depending on if a "%s" string is present in
1229 * the URI format, since that would indicate a quadtree-based map coordinate
1233 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
1236 vprintf("%s(%p, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1237 repo, zoom, tilex, tiley);
1241 retval = g_strdup_printf(repo->url,
1242 tilex, tiley, zoom - (MAX_ZOOM - 16));
1245 case REPOTYPE_XYZ_INV:
1246 retval = g_strdup_printf(repo->url,
1247 MAX_ZOOM + 1 - zoom, tilex, tiley);
1250 case REPOTYPE_XYZ_SIGNED:
1251 retval = g_strdup_printf(repo->url,
1253 (1 << (MAX_ZOOM - zoom)) - tiley - 1,
1254 zoom - (MAX_ZOOM - 17));
1257 case REPOTYPE_QUAD_QRST:
1259 gchar location[MAX_ZOOM + 2];
1260 map_convert_coords_to_quadtree_string(
1261 tilex, tiley, zoom, location, 't', "qrts");
1262 retval = g_strdup_printf(repo->url, location);
1266 case REPOTYPE_QUAD_ZERO:
1268 /* This is a zero-based quadtree URI. */
1269 gchar location[MAX_ZOOM + 2];
1270 map_convert_coords_to_quadtree_string(
1271 tilex, tiley, zoom, location, '\0', "0123");
1272 retval = g_strdup_printf(repo->url, location);
1277 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
1281 retval = g_strdup(repo->url);
1284 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
1289 mapdb_initiate_update_banner_idle()
1291 if(!_download_banner && _num_downloads != _curr_download)
1293 _download_banner = hildon_banner_show_progress(
1294 _window, NULL, _("Processing Maps"));
1295 /* If we're not connected, then hide the banner immediately. It will
1296 * be unhidden if/when we're connected. */
1297 if(!_conic_is_connected)
1298 gtk_widget_hide(_download_banner);
1304 * Initiate a download of the given xyz coordinates using the given buffer
1305 * as the URL. If the map already exists on disk, or if we are already
1306 * downloading the map, then this method does nothing.
1309 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
1310 gint update_type, gint batch_id, gint priority,
1311 ThreadLatch *refresh_latch)
1314 MapUpdateTask *old_mut;
1315 gboolean is_replacing = FALSE;
1316 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1317 repo->name, zoom, tilex, tiley, update_type);
1319 mut = g_slice_new(MapUpdateTask);
1322 /* Could not allocate memory. */
1323 g_printerr("Out of memory in allocation of update task #%d\n",
1324 _num_downloads + 1);
1330 mut->update_type = update_type;
1332 /* Lock the mutex if this is an auto-update. */
1333 if(update_type == MAP_UPDATE_AUTO)
1334 g_mutex_lock(_mut_priority_mutex);
1335 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
1337 /* Check if new mut is in a newer batch that the old mut.
1338 * We use vfs_result to indicate a MUT that is already in the process
1339 * of being downloaded. */
1340 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
1342 /* It is, so remove the old one so we can re-add this one. */
1343 g_hash_table_remove(_mut_exists_table, old_mut);
1344 g_tree_remove(_mut_priority_tree, old_mut);
1345 g_slice_free(MapUpdateTask, old_mut);
1346 is_replacing = TRUE;
1350 /* It's not, so just ignore it. */
1351 if(update_type == MAP_UPDATE_AUTO)
1352 g_mutex_unlock(_mut_priority_mutex);
1353 g_slice_free(MapUpdateTask, mut);
1354 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
1359 g_hash_table_insert(_mut_exists_table, mut, mut);
1362 mut->refresh_latch = refresh_latch;
1363 mut->priority = priority;
1364 mut->batch_id = batch_id;
1366 mut->vfs_result = -1;
1368 g_tree_insert(_mut_priority_tree, mut, mut);
1370 /* Unlock the mutex if this is an auto-update. */
1371 if(update_type == MAP_UPDATE_AUTO)
1372 g_mutex_unlock(_mut_priority_mutex);
1376 /* Increment download count and (possibly) display banner. */
1377 if(++_num_downloads == 20 && !_download_banner)
1378 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
1380 /* This doesn't need to be thread-safe. Extras in the pool don't
1381 * really make a difference. */
1382 if(g_thread_pool_get_num_threads(_mut_thread_pool)
1383 < g_thread_pool_get_max_threads(_mut_thread_pool))
1384 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1387 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1392 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1401 printf("%s()\n", __PRETTY_FUNCTION__);
1403 /* Make sure things are inititalized. */
1406 while(conic_ensure_connected())
1409 gboolean refresh_sent = FALSE;
1410 MapUpdateTask *mut = NULL;
1412 /* Get the next MUT from the mut tree. */
1413 g_mutex_lock(_mut_priority_mutex);
1414 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1417 /* No more MUTs to process. Return. */
1418 g_mutex_unlock(_mut_priority_mutex);
1421 /* Mark this MUT as "in-progress". */
1422 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1423 g_tree_remove(_mut_priority_tree, mut);
1424 g_mutex_unlock(_mut_priority_mutex);
1426 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1427 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1429 if(mut->repo != _curr_repo)
1431 /* Do nothing, except report that there is no error. */
1432 mut->vfs_result = GNOME_VFS_OK;
1434 else if(mut->update_type == MAP_UPDATE_DELETE)
1436 /* Easy - just delete the entry from the database. We don't care
1437 * about failures (sorry). */
1439 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1441 /* Report that there is no error. */
1442 mut->vfs_result = GNOME_VFS_OK;
1444 else for(retries = INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1446 gboolean exists = FALSE;
1450 GdkPixbufLoader *loader;
1452 gint zoom, tilex, tiley;
1453 GError *error = NULL;
1456 /* First check for existence. */
1457 exists = mut->repo->db
1458 ? mapdb_exists(mut->repo, mut->zoom,
1459 mut->tilex, mut->tiley)
1461 if(exists && mut->update_type == MAP_UPDATE_ADD)
1463 /* Map already exists, and we're not going to overwrite. */
1464 /* Report that there is no error. */
1465 mut->vfs_result = GNOME_VFS_OK;
1469 /* First check for existence. */
1470 if(mut->update_type == MAP_UPDATE_ADD)
1472 /* We don't want to overwrite, so check for existence. */
1473 /* Map already exists, and we're not going to overwrite. */
1474 if(mapdb_exists(mut->repo, mut->zoom,
1475 mut->tilex,mut->tiley))
1477 /* Report that there is no error. */
1478 mut->vfs_result = GNOME_VFS_OK;
1484 /* First, construct the URL from which we will get the data. */
1485 src_url = map_construct_url(mut->repo, mut->zoom,
1486 mut->tilex, mut->tiley);
1488 /* Now, attempt to read the entire contents of the URL. */
1489 mut->vfs_result = gnome_vfs_read_entire_file(
1490 src_url, &size, &bytes);
1492 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1495 printf("Error reading URL: %s\n",
1496 gnome_vfs_result_to_string(mut->vfs_result));
1500 /* usleep(100000); DEBUG */
1502 /* Attempt to parse the bytes into a pixbuf. */
1503 loader = gdk_pixbuf_loader_new();
1504 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1505 gdk_pixbuf_loader_close(loader, &error);
1506 if(error || (NULL == (mut->pixbuf = g_object_ref(
1507 gdk_pixbuf_loader_get_pixbuf(loader)))))
1509 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1511 g_object_unref(mut->pixbuf);
1514 g_object_unref(loader);
1515 printf("Error parsing pixbuf: %s\n",
1516 error ? error->message : "?");
1519 g_object_unref(loader);
1521 /* Copy database-relevant mut data before we release it. */
1527 /* Pass the mut to the GTK thread for redrawing, but only if a
1528 * redraw isn't already in the pipeline. */
1529 if(mut->refresh_latch)
1531 /* Wait until the latch is open. */
1532 g_mutex_lock(mut->refresh_latch->mutex);
1533 while(!mut->refresh_latch->is_open)
1535 g_cond_wait(mut->refresh_latch->cond,
1536 mut->refresh_latch->mutex);
1538 /* Latch is open. Decrement the number of waiters and
1539 * check if we're the last waiter to run. */
1540 if(mut->refresh_latch->is_done_adding_tasks)
1542 if(++mut->refresh_latch->num_done
1543 == mut->refresh_latch->num_tasks)
1545 /* Last waiter. Free the latch resources. */
1546 g_mutex_unlock(mut->refresh_latch->mutex);
1547 g_cond_free(mut->refresh_latch->cond);
1548 g_mutex_free(mut->refresh_latch->mutex);
1549 g_slice_free(ThreadLatch, mut->refresh_latch);
1550 mut->refresh_latch = NULL;
1554 /* Not the last waiter. Signal the next waiter.*/
1555 g_cond_signal(mut->refresh_latch->cond);
1556 g_mutex_unlock(mut->refresh_latch->mutex);
1560 g_mutex_unlock(mut->refresh_latch->mutex);
1563 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1564 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1565 refresh_sent = TRUE;
1567 /* DO NOT USE mut FROM THIS POINT ON. */
1569 /* Also attempt to add to the database. */
1570 mapdb_update(exists, repo, zoom,
1571 tilex, tiley, bytes, size);
1579 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1580 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1583 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1588 mut_exists_hashfunc(const MapUpdateTask *a)
1590 gint sum = a->zoom + a->tilex + a->tiley + a->update_type;
1591 return g_int_hash(&sum);
1595 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1597 return (a->tilex == b->tilex
1598 && a->tiley == b->tiley
1599 && a->zoom == b->zoom
1600 && a->update_type == b->update_type);
1604 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1606 /* The update_type enum is sorted in order of ascending priority. */
1607 gint diff = (b->update_type - a->update_type);
1610 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1613 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1617 /* At this point, we don't care, so just pick arbitrarily. */
1618 diff = (a->tilex - b->tilex);
1621 diff = (a->tiley - b->tiley);
1624 return (a->zoom - b->zoom);
1628 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1630 printf("%s()\n", __PRETTY_FUNCTION__);
1631 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1632 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1633 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1638 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1642 printf("%s()\n", __PRETTY_FUNCTION__);
1644 dialog = GTK_WIDGET(
1645 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1646 GTK_FILE_CHOOSER_ACTION_SAVE));
1648 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1649 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1651 /* Work around a bug in HildonFileChooserDialog. */
1652 basename = g_path_get_basename(
1653 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1654 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1655 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1657 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1659 gchar *filename = gtk_file_chooser_get_filename(
1660 GTK_FILE_CHOOSER(dialog));
1661 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1665 gtk_widget_destroy(dialog);
1667 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1672 repoman_compact_complete_idle(CompactInfo *ci)
1674 printf("%s()\n", __PRETTY_FUNCTION__);
1676 gtk_widget_destroy(GTK_WIDGET(ci->banner));
1677 popup_error(ci->dialog, ci->status_msg);
1678 gtk_widget_destroy(ci->dialog);
1681 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1686 thread_repoman_compact(CompactInfo *ci)
1689 printf("%s()\n", __PRETTY_FUNCTION__);
1691 if(!(db = gdbm_open((gchar*)ci->db_filename, 0, GDBM_WRITER | GDBM_FAST,
1693 ci->status_msg = _("Failed to open map database for compacting.");
1696 if(gdbm_reorganize(db))
1697 ci->status_msg = _("An error occurred while trying to "
1698 "compact the database.");
1700 ci->status_msg = _("Successfully compacted database.");
1704 g_idle_add((GSourceFunc)repoman_compact_complete_idle, ci);
1706 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1710 repoman_dialog_compact(GtkWidget *widget, BrowseInfo *browse_info)
1714 printf("%s()\n", __PRETTY_FUNCTION__);
1716 ci = g_new0(CompactInfo, 1);
1718 ci->dialog = gtk_dialog_new_with_buttons(_("Compact Database"),
1719 GTK_WINDOW(browse_info->dialog), GTK_DIALOG_MODAL,
1720 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1721 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1724 sw = gtk_scrolled_window_new (NULL, NULL);
1725 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1726 GTK_SHADOW_ETCHED_IN);
1727 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1730 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ci->dialog)->vbox),
1733 gtk_container_add(GTK_CONTAINER(sw), ci->txt = gtk_text_view_new());
1734 gtk_text_view_set_editable(GTK_TEXT_VIEW(ci->txt), FALSE);
1735 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ci->txt), FALSE);
1736 gtk_text_buffer_set_text(
1737 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1738 _("Generally, deleted maps create an empty space in the "
1739 "database that is later reused when downloading new maps. "
1740 "Compacting the database reorganizes it such that all "
1741 "that blank space is eliminated. This is the only way "
1742 "that the size of the database can decrease.\n"
1743 "This reorganization requires creating a new file and "
1744 "inserting all the maps in the old database file into the "
1745 "new file. The new file is then renamed to the same name "
1746 "as the old file and dbf is updated to contain all the "
1747 "correct information about the new file. Note that this "
1748 "can require free space on disk of an amount up to the size "
1749 "of the map database.\n"
1750 "This process may take several minutes, especially if "
1751 "your map database is large. As a rough estimate, you can "
1752 "expect to wait approximately 2-5 seconds per megabyte of "
1753 "map data (34-85 minutes per gigabyte). There is no progress "
1754 "indicator, although you can watch the new file grow in any "
1755 "file manager. Do not attempt to close Maemo Mapper while "
1756 "the compacting operation is in progress."),
1760 gtk_text_buffer_get_iter_at_offset(
1761 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1763 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ci->txt),
1764 &iter, 0.0, FALSE, 0, 0);
1767 gtk_widget_set_size_request(GTK_WIDGET(sw), 600, 200);
1768 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(ci->txt), GTK_WRAP_WORD);
1770 gtk_widget_show_all(ci->dialog);
1772 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(ci->dialog)))
1774 gtk_widget_set_sensitive(GTK_DIALOG(ci->dialog)->action_area, FALSE);
1775 ci->db_filename = gtk_entry_get_text(GTK_ENTRY(browse_info->txt));
1776 ci->banner = hildon_banner_show_animation(ci->dialog, NULL,
1777 _("Compacting database..."));
1779 g_thread_create((GThreadFunc)thread_repoman_compact, ci, FALSE, NULL);
1783 gtk_widget_destroy(ci->dialog);
1786 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1790 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1792 static GtkWidget *hbox = NULL;
1793 static GtkWidget *label = NULL;
1794 static GtkWidget *txt_name = NULL;
1795 static GtkWidget *dialog = NULL;
1796 printf("%s()\n", __PRETTY_FUNCTION__);
1800 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1801 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1802 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1803 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1806 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1807 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1809 gtk_box_pack_start(GTK_BOX(hbox),
1810 label = gtk_label_new(_("Name")),
1812 gtk_box_pack_start(GTK_BOX(hbox),
1813 txt_name = gtk_entry_new(),
1818 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1819 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1820 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1823 gtk_widget_show_all(dialog);
1825 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1827 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1828 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1830 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1831 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1832 active, g_strdup(rei->name));
1833 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1834 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1838 gtk_widget_hide(dialog);
1840 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1845 repoman_delete(RepoManInfo *rmi, gint index)
1847 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1848 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1849 rmi->repo_edits = g_list_remove_link(
1851 g_list_nth(rmi->repo_edits, index));
1855 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1859 printf("%s()\n", __PRETTY_FUNCTION__);
1861 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1862 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1865 popup_error(rmi->dialog,
1866 _("Cannot delete the last repository - there must be at"
1867 " lease one repository."));
1868 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1872 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1873 _("Confirm delete of repository"),
1874 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1876 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1878 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1880 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1881 repoman_delete(rmi, active);
1882 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1886 gtk_widget_destroy(confirm);
1891 static RepoEditInfo*
1892 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
1898 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
1899 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
1904 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
1905 vbox = gtk_vbox_new(FALSE, 4),
1906 gtk_label_new(name));
1908 /* Prevent destruction of notebook page, because the destruction causes
1909 * a seg fault (!?!?) */
1910 gtk_object_ref(GTK_OBJECT(vbox));
1912 gtk_box_pack_start(GTK_BOX(vbox),
1913 table = gtk_table_new(2, 2, FALSE),
1915 /* Map download URI. */
1916 gtk_table_attach(GTK_TABLE(table),
1917 label = gtk_label_new(_("URL Format")),
1918 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1919 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1920 gtk_table_attach(GTK_TABLE(table),
1921 rei->txt_url = gtk_entry_new(),
1922 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1924 /* Map Directory. */
1925 gtk_table_attach(GTK_TABLE(table),
1926 label = gtk_label_new(_("Cache DB")),
1927 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1928 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1929 gtk_table_attach(GTK_TABLE(table),
1930 hbox = gtk_hbox_new(FALSE, 4),
1931 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1932 gtk_box_pack_start(GTK_BOX(hbox),
1933 rei->txt_db_filename = gtk_entry_new(),
1935 gtk_box_pack_start(GTK_BOX(hbox),
1936 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
1938 gtk_box_pack_start(GTK_BOX(hbox),
1939 rei->btn_compact = gtk_button_new_with_label(_("Compact...")),
1942 /* Initialize cache dir */
1944 gchar buffer[BUFFER_SIZE];
1945 snprintf(buffer, sizeof(buffer), "%s.db", name);
1946 gchar *db_base = gnome_vfs_expand_initial_tilde(
1947 REPO_DEFAULT_CACHE_BASE);
1948 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
1950 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
1951 g_free(db_filename);
1955 gtk_box_pack_start(GTK_BOX(vbox),
1956 table = gtk_table_new(3, 2, FALSE),
1959 /* Download Zoom Steps. */
1960 gtk_table_attach(GTK_TABLE(table),
1961 label = gtk_label_new(_("Download Zoom Steps")),
1962 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1963 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1964 gtk_table_attach(GTK_TABLE(table),
1965 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1966 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1967 gtk_container_add(GTK_CONTAINER(label),
1968 rei->num_dl_zoom_steps = hildon_controlbar_new());
1969 hildon_controlbar_set_range(
1970 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
1971 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1972 REPO_DEFAULT_DL_ZOOM_STEPS);
1973 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
1975 /* Download Zoom Steps. */
1976 gtk_table_attach(GTK_TABLE(table),
1977 label = gtk_label_new(_("View Zoom Steps")),
1978 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1979 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1980 gtk_table_attach(GTK_TABLE(table),
1981 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1982 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
1983 gtk_container_add(GTK_CONTAINER(label),
1984 rei->num_view_zoom_steps = hildon_controlbar_new());
1985 hildon_controlbar_set_range(
1986 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
1987 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1988 REPO_DEFAULT_VIEW_ZOOM_STEPS);
1989 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
1991 gtk_table_attach(GTK_TABLE(table),
1992 label = gtk_vseparator_new(),
1993 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
1996 gtk_table_attach(GTK_TABLE(table),
1997 rei->chk_double_size = gtk_check_button_new_with_label(
1998 _("Double Pixels")),
1999 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
2000 gtk_toggle_button_set_active(
2001 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
2004 gtk_table_attach(GTK_TABLE(table),
2005 rei->chk_nextable = gtk_check_button_new_with_label(
2007 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
2008 gtk_toggle_button_set_active(
2009 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
2011 /* Downloadable Zoom Levels. */
2012 gtk_table_attach(GTK_TABLE(table),
2013 label = gtk_label_new(_("Downloadable Zooms:")),
2014 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2015 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2016 gtk_table_attach(GTK_TABLE(table),
2017 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2018 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
2019 gtk_container_add(GTK_CONTAINER(label),
2020 hbox = gtk_hbox_new(FALSE, 4));
2021 gtk_box_pack_start(GTK_BOX(hbox),
2022 label = gtk_label_new(_("Min.")),
2024 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2025 gtk_box_pack_start(GTK_BOX(hbox),
2026 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2028 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
2029 gtk_box_pack_start(GTK_BOX(hbox),
2030 label = gtk_label_new(""),
2032 gtk_box_pack_start(GTK_BOX(hbox),
2033 label = gtk_label_new(_("Max.")),
2035 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2036 gtk_box_pack_start(GTK_BOX(hbox),
2037 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2039 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
2041 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
2043 /* Connect signals. */
2044 rei->browse_info.dialog = rmi->dialog;
2045 rei->browse_info.txt = rei->txt_db_filename;
2046 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
2047 G_CALLBACK(repoman_dialog_browse),
2049 g_signal_connect(G_OBJECT(rei->btn_compact), "clicked",
2050 G_CALLBACK(repoman_dialog_compact),
2053 gtk_widget_show_all(vbox);
2055 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
2056 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
2057 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
2058 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
2061 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2066 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
2068 static GtkWidget *hbox = NULL;
2069 static GtkWidget *label = NULL;
2070 static GtkWidget *txt_name = NULL;
2071 static GtkWidget *dialog = NULL;
2072 printf("%s()\n", __PRETTY_FUNCTION__);
2076 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
2077 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
2078 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2079 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2082 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2083 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2085 gtk_box_pack_start(GTK_BOX(hbox),
2086 label = gtk_label_new(_("Name")),
2088 gtk_box_pack_start(GTK_BOX(hbox),
2089 txt_name = gtk_entry_new(),
2093 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2095 gtk_widget_show_all(dialog);
2097 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2099 repoman_dialog_add_repo(rmi,
2100 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2104 gtk_widget_hide(dialog);
2106 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2111 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
2114 printf("%s()\n", __PRETTY_FUNCTION__);
2116 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
2117 _("Replace all repositories with the default repository?"));
2119 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2121 /* First, delete all existing repositories. */
2122 while(rmi->repo_edits)
2123 repoman_delete(rmi, 0);
2125 /* Now, add the default repository. */
2126 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
2128 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
2129 REPO_DEFAULT_MAP_URI);
2131 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
2133 gtk_widget_destroy(confirm);
2135 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2140 repoman_download(GtkWidget *widget, RepoManInfo *rmi)
2143 printf("%s()\n", __PRETTY_FUNCTION__);
2145 confirm = hildon_note_new_confirmation(
2146 GTK_WINDOW(rmi->dialog),
2147 _("Maemo Mapper will now download and add a list of "
2148 "possibly-duplicate repositories from the internet. "
2151 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2157 GnomeVFSResult vfs_result;
2158 printf("%s()\n", __PRETTY_FUNCTION__);
2160 /* Get repo config file from www.gnuite.com. */
2161 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2162 "http://www.gnuite.com/nokia770/maemo-mapper/repos.txt",
2165 popup_error(rmi->dialog,
2166 _("An error occurred while retrieving the repositories. "
2167 "The web service may be temporarily down."));
2168 g_printerr("Error while download repositories: %s\n",
2169 gnome_vfs_result_to_string(vfs_result));
2171 /* Parse each line as a reposotory. */
2174 for(head = bytes; head && *head; head = tail)
2176 gchar buffer[BUFFER_SIZE];
2179 tail = strchr(head, '\n');
2182 rd = settings_parse_repo(head);
2183 snprintf(buffer, sizeof(buffer), "%s.db", rd->db_filename);
2184 rei = repoman_dialog_add_repo(
2185 rmi, g_strdup(rd->name));
2186 /* Initialize fields with data from the RepoData object. */
2187 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2188 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), buffer);
2189 hildon_controlbar_set_value(
2190 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2192 hildon_controlbar_set_value(
2193 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2194 rd->view_zoom_steps);
2195 gtk_toggle_button_set_active(
2196 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2198 gtk_toggle_button_set_active(
2199 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2201 hildon_number_editor_set_value(
2202 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2204 hildon_number_editor_set_value(
2205 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2211 gtk_widget_destroy(confirm);
2213 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2220 static RepoManInfo rmi;
2221 static GtkWidget *dialog = NULL;
2222 static GtkWidget *hbox = NULL;
2223 static GtkWidget *btn_rename = NULL;
2224 static GtkWidget *btn_delete = NULL;
2225 static GtkWidget *btn_new = NULL;
2226 static GtkWidget *btn_reset = NULL;
2227 static GtkWidget *btn_download = NULL;
2228 gint i, curr_repo_index = 0;
2230 printf("%s()\n", __PRETTY_FUNCTION__);
2234 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
2235 _("Manage Repositories"),
2236 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2237 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2240 /* Enable the help button. */
2242 hildon_help_dialog_help_enable(
2244 ossohelp_dialog_help_enable(
2246 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
2249 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2250 btn_reset = gtk_button_new_with_label(_("Reset...")));
2251 g_signal_connect(G_OBJECT(btn_reset), "clicked",
2252 G_CALLBACK(repoman_reset), &rmi);
2254 /* Download button. */
2255 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2256 btn_download = gtk_button_new_with_label(_("Download...")));
2257 g_signal_connect(G_OBJECT(btn_download), "clicked",
2258 G_CALLBACK(repoman_download), &rmi);
2260 /* Cancel button. */
2261 gtk_dialog_add_button(GTK_DIALOG(dialog),
2262 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2264 hbox = gtk_hbox_new(FALSE, 4);
2266 gtk_box_pack_start(GTK_BOX(hbox),
2267 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
2269 gtk_box_pack_start(GTK_BOX(hbox),
2270 gtk_vseparator_new(), FALSE, FALSE, 4);
2271 gtk_box_pack_start(GTK_BOX(hbox),
2272 btn_rename = gtk_button_new_with_label(_("Rename...")),
2274 gtk_box_pack_start(GTK_BOX(hbox),
2275 btn_delete = gtk_button_new_with_label(_("Delete...")),
2277 gtk_box_pack_start(GTK_BOX(hbox),
2278 btn_new = gtk_button_new_with_label(_("New...")),
2281 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2282 hbox, FALSE, FALSE, 4);
2284 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2285 gtk_hseparator_new(), TRUE, TRUE, 4);
2286 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2287 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
2289 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
2290 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
2292 rmi.repo_edits = NULL;
2294 /* Connect signals. */
2295 g_signal_connect(G_OBJECT(btn_rename), "clicked",
2296 G_CALLBACK(repoman_dialog_rename), &rmi);
2297 g_signal_connect(G_OBJECT(btn_delete), "clicked",
2298 G_CALLBACK(repoman_dialog_delete), &rmi);
2299 g_signal_connect(G_OBJECT(btn_new), "clicked",
2300 G_CALLBACK(repoman_dialog_new), &rmi);
2301 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
2302 G_CALLBACK(repoman_dialog_select), &rmi);
2305 /* Populate combo box and pages in notebook. */
2306 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
2308 RepoData *rd = (RepoData*)curr->data;
2309 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
2311 /* Initialize fields with data from the RepoData object. */
2312 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2313 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
2315 hildon_controlbar_set_value(
2316 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2318 hildon_controlbar_set_value(
2319 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2320 rd->view_zoom_steps);
2321 gtk_toggle_button_set_active(
2322 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2324 gtk_toggle_button_set_active(
2325 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2327 hildon_number_editor_set_value(
2328 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2330 hildon_number_editor_set_value(
2331 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2333 if(rd == _curr_repo)
2334 curr_repo_index = i;
2337 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
2338 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
2340 gtk_widget_show_all(dialog);
2342 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2344 /* Iterate through repos and verify each. */
2345 gboolean verified = TRUE;
2348 gchar *old_curr_repo_name = _curr_repo->name;
2350 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2352 /* Check the ranges for the min and max zoom levels. */
2353 RepoEditInfo *rei = curr->data;
2354 if(hildon_number_editor_get_value(
2355 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
2356 < hildon_number_editor_get_value(
2357 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
2365 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
2367 _("Minimum Downloadable Zoom must be less than "
2368 "Maximum Downloadable Zoom."));
2372 /* We're good to replace. Remove old _repo_list menu items. */
2373 menu_maps_remove_repos();
2374 /* But keep the repo list in memory, in case downloads are using it. */
2377 /* Write new _repo_list. */
2378 curr_repo_index = gtk_combo_box_get_active(
2379 GTK_COMBO_BOX(rmi.cmb_repos));
2381 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2383 RepoEditInfo *rei = curr->data;
2384 RepoData *rd = g_new(RepoData, 1);
2385 rd->name = g_strdup(rei->name);
2386 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
2387 rd->db_filename = gnome_vfs_expand_initial_tilde(
2388 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
2389 rd->dl_zoom_steps = hildon_controlbar_get_value(
2390 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
2391 rd->view_zoom_steps = hildon_controlbar_get_value(
2392 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
2393 rd->double_size = gtk_toggle_button_get_active(
2394 GTK_TOGGLE_BUTTON(rei->chk_double_size));
2395 rd->nextable = gtk_toggle_button_get_active(
2396 GTK_TOGGLE_BUTTON(rei->chk_nextable));
2397 rd->min_zoom = hildon_number_editor_get_value(
2398 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
2399 rd->max_zoom = hildon_number_editor_get_value(
2400 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
2403 _repo_list = g_list_append(_repo_list, rd);
2405 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
2407 else if(i == curr_repo_index)
2411 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
2412 menu_maps_add_repos();
2418 gtk_widget_hide(dialog);
2420 /* Clear out the notebook entries. */
2421 while(rmi.repo_edits)
2422 repoman_delete(&rmi, 0);
2424 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
2426 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2431 mapman_by_area(gdouble start_lat, gdouble start_lon,
2432 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
2433 MapUpdateType update_type,
2434 gint download_batch_id)
2436 gint start_unitx, start_unity, end_unitx, end_unity;
2441 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
2444 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
2445 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
2447 /* Swap if they specified flipped lats or lons. */
2448 if(start_unitx > end_unitx)
2450 gint swap = start_unitx;
2451 start_unitx = end_unitx;
2454 if(start_unity > end_unity)
2456 gint swap = start_unity;
2457 start_unity = end_unity;
2461 /* First, get the number of maps to download. */
2462 for(z = 0; z <= MAX_ZOOM; ++z)
2464 if(gtk_toggle_button_get_active(
2465 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2467 gint start_tilex, start_tiley, end_tilex, end_tiley;
2468 start_tilex = unit2ztile(start_unitx, z);
2469 start_tiley = unit2ztile(start_unity, z);
2470 end_tilex = unit2ztile(end_unitx, z);
2471 end_tiley = unit2ztile(end_unity, z);
2472 num_maps += (end_tilex - start_tilex + 1)
2473 * (end_tiley - start_tiley + 1);
2477 if(update_type == MAP_UPDATE_DELETE)
2479 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
2480 num_maps, _("maps "));
2484 snprintf(buffer, sizeof(buffer),
2485 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2486 num_maps, _("maps"), _("up to about"),
2487 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2489 confirm = hildon_note_new_confirmation(
2490 GTK_WINDOW(mapman_info->dialog), buffer);
2492 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2494 gtk_widget_destroy(confirm);
2495 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2499 g_mutex_lock(_mut_priority_mutex);
2500 for(z = 0; z <= MAX_ZOOM; ++z)
2502 if(gtk_toggle_button_get_active(
2503 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2505 gint start_tilex, start_tiley, end_tilex, end_tiley;
2507 start_tilex = unit2ztile(start_unitx, z);
2508 start_tiley = unit2ztile(start_unity, z);
2509 end_tilex = unit2ztile(end_unitx, z);
2510 end_tiley = unit2ztile(end_unity, z);
2511 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
2513 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
2515 /* Make sure this tile is even possible. */
2516 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
2517 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
2519 mapdb_initiate_update(_curr_repo, z, tilex, tiley,
2520 update_type, download_batch_id,
2521 (abs(tilex - unit2tile(_next_center.unitx))
2522 + abs(tiley - unit2tile(_next_center.unity))),
2529 g_mutex_unlock(_mut_priority_mutex);
2531 gtk_widget_destroy(confirm);
2532 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2537 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
2538 gint download_batch_id)
2541 gint prev_tilex, prev_tiley, num_maps = 0, z;
2544 gint radius = hildon_number_editor_get_value(
2545 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
2546 printf("%s()\n", __PRETTY_FUNCTION__);
2548 /* First, get the number of maps to download. */
2549 for(z = 0; z <= MAX_ZOOM; ++z)
2551 if(gtk_toggle_button_get_active(
2552 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2556 for(curr = _route.head - 1; curr++ != _route.tail; )
2560 gint tilex = unit2ztile(curr->unitx, z);
2561 gint tiley = unit2ztile(curr->unity, z);
2562 if(tilex != prev_tilex || tiley != prev_tiley)
2565 num_maps += (abs((gint)tilex - prev_tilex) + 1)
2566 * (abs((gint)tiley - prev_tiley) + 1) - 1;
2574 num_maps *= 0.625 * pow(radius + 1, 1.85);
2576 if(update_type == MAP_UPDATE_DELETE)
2578 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
2579 _("Confirm DELETION of"), _("about"),
2580 num_maps, _("maps "));
2584 snprintf(buffer, sizeof(buffer),
2585 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2587 num_maps, _("maps"), _("up to about"),
2588 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2590 confirm = hildon_note_new_confirmation(
2591 GTK_WINDOW(mapman_info->dialog), buffer);
2593 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2595 gtk_widget_destroy(confirm);
2596 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2600 /* Now, do the actual download. */
2601 g_mutex_lock(_mut_priority_mutex);
2602 for(z = 0; z <= MAX_ZOOM; ++z)
2604 if(gtk_toggle_button_get_active(
2605 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2609 for(curr = _route.head - 1; curr++ != _route.tail; )
2613 gint tilex = unit2ztile(curr->unitx, z);
2614 gint tiley = unit2ztile(curr->unity, z);
2615 if(tilex != prev_tilex || tiley != prev_tiley)
2617 gint minx, miny, maxx, maxy, x, y;
2620 minx = MIN(tilex, prev_tilex) - radius;
2621 miny = MIN(tiley, prev_tiley) - radius;
2622 maxx = MAX(tilex, prev_tilex) + radius;
2623 maxy = MAX(tiley, prev_tiley) + radius;
2627 minx = tilex - radius;
2628 miny = tiley - radius;
2629 maxx = tilex + radius;
2630 maxy = tiley + radius;
2632 for(x = minx; x <= maxx; x++)
2634 for(y = miny; y <= maxy; y++)
2636 /* Make sure this tile is even possible. */
2638 < unit2ztile(WORLD_SIZE_UNITS, z)
2640 < unit2ztile(WORLD_SIZE_UNITS, z))
2642 mapdb_initiate_update(_curr_repo, z, x, y,
2643 update_type, download_batch_id,
2644 (abs(tilex - unit2tile(
2645 _next_center.unitx))
2646 + abs(tiley - unit2tile(
2647 _next_center.unity))),
2659 g_mutex_unlock(_mut_priority_mutex);
2660 _route_dl_radius = radius;
2661 gtk_widget_destroy(confirm);
2662 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2667 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
2670 printf("%s()\n", __PRETTY_FUNCTION__);
2671 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
2672 /* This is the second page (the "Zoom" page) - clear the checks. */
2673 for(z = 0; z <= MAX_ZOOM; ++z)
2674 gtk_toggle_button_set_active(
2675 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
2678 /* This is the first page (the "Area" page) - clear the text fields. */
2679 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
2680 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
2681 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
2682 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
2684 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2687 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
2689 printf("%s()\n", __PRETTY_FUNCTION__);
2690 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
2691 gtk_toggle_button_get_active(
2692 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
2694 if(gtk_toggle_button_get_active(
2695 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
2696 gtk_widget_show(mapman_info->tbl_area);
2697 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
2698 gtk_widget_hide(mapman_info->tbl_area);
2700 gtk_widget_set_sensitive(mapman_info->num_route_radius,
2701 gtk_toggle_button_get_active(
2702 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
2703 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2709 static GtkWidget *dialog = NULL;
2710 static GtkWidget *vbox = NULL;
2711 static GtkWidget *hbox = NULL;
2712 static GtkWidget *table = NULL;
2713 static GtkWidget *label = NULL;
2714 static GtkWidget *button = NULL;
2715 static GtkWidget *lbl_gps_lat = NULL;
2716 static GtkWidget *lbl_gps_lon = NULL;
2717 static GtkWidget *lbl_center_lat = NULL;
2718 static GtkWidget *lbl_center_lon = NULL;
2719 static MapmanInfo mapman_info;
2723 printf("%s()\n", __PRETTY_FUNCTION__);
2727 popup_error(_window, "To manage maps, you must set a valid repository "
2728 "database filename in the \"Manage Repositories\" dialog.");
2729 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2735 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
2737 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2738 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2741 /* Enable the help button. */
2743 hildon_help_dialog_help_enable(
2745 ossohelp_dialog_help_enable(
2747 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
2750 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2751 button = gtk_button_new_with_label(_("Clear")));
2752 g_signal_connect(G_OBJECT(button), "clicked",
2753 G_CALLBACK(mapman_clear), &mapman_info);
2755 /* Cancel button. */
2756 gtk_dialog_add_button(GTK_DIALOG(dialog),
2757 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2759 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2760 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
2763 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2764 vbox = gtk_vbox_new(FALSE, 2),
2765 label = gtk_label_new(_("Setup")));
2766 gtk_notebook_set_tab_label_packing(
2767 GTK_NOTEBOOK(mapman_info.notebook), vbox,
2768 FALSE, FALSE, GTK_PACK_START);
2770 gtk_box_pack_start(GTK_BOX(vbox),
2771 hbox = gtk_hbox_new(FALSE, 4),
2773 gtk_box_pack_start(GTK_BOX(hbox),
2774 mapman_info.rad_download = gtk_radio_button_new_with_label(
2775 NULL,_("Download Maps")),
2777 gtk_box_pack_start(GTK_BOX(hbox),
2778 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2780 gtk_container_add(GTK_CONTAINER(label),
2781 mapman_info.chk_overwrite
2782 = gtk_check_button_new_with_label(_("Overwrite"))),
2784 gtk_box_pack_start(GTK_BOX(vbox),
2785 mapman_info.rad_delete
2786 = gtk_radio_button_new_with_label_from_widget(
2787 GTK_RADIO_BUTTON(mapman_info.rad_download),
2791 gtk_box_pack_start(GTK_BOX(vbox),
2792 gtk_hseparator_new(),
2795 gtk_box_pack_start(GTK_BOX(vbox),
2796 mapman_info.rad_by_area
2797 = gtk_radio_button_new_with_label(NULL,
2798 _("By Area (see tab)")),
2800 gtk_box_pack_start(GTK_BOX(vbox),
2801 hbox = gtk_hbox_new(FALSE, 4),
2803 gtk_box_pack_start(GTK_BOX(hbox),
2804 mapman_info.rad_by_route
2805 = gtk_radio_button_new_with_label_from_widget(
2806 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
2807 _("Along Route - Radius (tiles):")),
2809 gtk_box_pack_start(GTK_BOX(hbox),
2810 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
2812 hildon_number_editor_set_value(
2813 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
2818 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2819 table = gtk_table_new(5, 5, FALSE),
2820 label = gtk_label_new(_("Zoom")));
2821 gtk_notebook_set_tab_label_packing(
2822 GTK_NOTEBOOK(mapman_info.notebook), table,
2823 FALSE, FALSE, GTK_PACK_START);
2824 gtk_table_attach(GTK_TABLE(table),
2825 label = gtk_label_new(
2826 _("Zoom Levels to Download: (0 = most detail)")),
2827 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
2828 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2829 snprintf(buffer, sizeof(buffer), "%d", 0);
2830 gtk_table_attach(GTK_TABLE(table),
2831 mapman_info.chk_zoom_levels[0]
2832 = gtk_check_button_new_with_label(buffer),
2833 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
2834 for(z = 0; z < MAX_ZOOM; ++z)
2836 snprintf(buffer, sizeof(buffer), "%d", z + 1);
2837 gtk_table_attach(GTK_TABLE(table),
2838 mapman_info.chk_zoom_levels[z + 1]
2839 = gtk_check_button_new_with_label(buffer),
2840 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
2845 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2846 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
2847 label = gtk_label_new(_("Area")));
2849 /* Label Columns. */
2850 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2851 label = gtk_label_new(_("Latitude")),
2852 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
2853 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2854 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2855 label = gtk_label_new(_("Longitude")),
2856 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
2857 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2860 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2861 label = gtk_label_new(_("GPS Location")),
2862 0, 1, 1, 2, GTK_FILL, 0, 4, 0);
2863 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2864 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2865 lbl_gps_lat = gtk_label_new(""),
2866 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
2867 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
2868 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
2869 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2870 lbl_gps_lon = gtk_label_new(""),
2871 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
2872 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
2873 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
2876 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2877 label = gtk_label_new(_("View Center")),
2878 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
2879 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2880 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2881 lbl_center_lat = gtk_label_new(""),
2882 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
2883 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
2884 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
2885 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2886 lbl_center_lon = gtk_label_new(""),
2887 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
2888 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
2889 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
2891 /* default values for Top Left and Bottom Right are defined by the
2892 * rectangle of the current and the previous Center */
2895 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2896 label = gtk_label_new(_("Top-Left")),
2897 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
2898 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2899 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2900 mapman_info.txt_topleft_lat = gtk_entry_new(),
2901 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
2902 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
2903 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
2904 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2906 "hildon-input-mode",
2907 HILDON_GTK_INPUT_MODE_FULL, NULL);
2909 HILDON_INPUT_MODE_HINT,
2910 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2911 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2915 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2916 mapman_info.txt_topleft_lon = gtk_entry_new(),
2917 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
2918 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
2919 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
2920 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2922 "hildon-input-mode",
2923 HILDON_GTK_INPUT_MODE_FULL, NULL);
2925 HILDON_INPUT_MODE_HINT,
2926 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2927 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2933 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2934 label = gtk_label_new(_("Bottom-Right")),
2935 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
2936 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2937 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2938 mapman_info.txt_botright_lat = gtk_entry_new(),
2939 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
2940 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2941 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
2942 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2944 "hildon-input-mode",
2945 HILDON_GTK_INPUT_MODE_FULL, NULL);
2947 HILDON_INPUT_MODE_HINT,
2948 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2949 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2953 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2954 mapman_info.txt_botright_lon = gtk_entry_new(),
2955 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
2956 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2957 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
2958 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2960 "hildon-input-mode",
2961 HILDON_GTK_INPUT_MODE_FULL, NULL);
2963 HILDON_INPUT_MODE_HINT,
2964 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2965 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2970 /* Default action is to download by area. */
2971 gtk_toggle_button_set_active(
2972 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
2974 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
2975 G_CALLBACK(mapman_update_state), &mapman_info);
2976 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
2977 G_CALLBACK(mapman_update_state), &mapman_info);
2978 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
2979 G_CALLBACK(mapman_update_state), &mapman_info);
2980 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
2981 G_CALLBACK(mapman_update_state), &mapman_info);
2984 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
2985 * output (and parsed) as locale-dependent. */
2987 gtk_widget_set_sensitive(mapman_info.rad_by_route,
2988 _route.head != _route.tail);
2990 lat_format(_gps.lat, buffer);
2991 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
2992 lon_format(_gps.lon, buffer);
2993 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
2995 unit2latlon(_center.unitx, _center.unity, lat, lon);
2996 lat_format(lat, buffer);
2997 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
2998 lon_format(lon, buffer);
2999 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
3001 /* Initialize to the bounds of the screen. */
3003 _center.unitx - pixel2unit(MAX(_view_width_pixels,
3004 _view_height_pixels) / 2),
3005 _center.unity - pixel2unit(MAX(_view_width_pixels,
3006 _view_height_pixels) / 2), lat, lon);
3007 BOUND(lat, -90.f, 90.f);
3008 BOUND(lon, -180.f, 180.f);
3009 lat_format(lat, buffer);
3010 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
3011 lon_format(lon, buffer);
3012 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
3015 _center.unitx + pixel2unit(MAX(_view_width_pixels,
3016 _view_height_pixels) / 2),
3017 _center.unity + pixel2unit(MAX(_view_width_pixels,
3018 _view_height_pixels) / 2), lat, lon);
3019 BOUND(lat, -90.f, 90.f);
3020 BOUND(lon, -180.f, 180.f);
3021 lat_format(lat, buffer);
3022 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
3023 lon_format(lon, buffer);
3024 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
3026 /* Initialize zoom levels. */
3029 for(i = 0; i <= MAX_ZOOM; i++)
3031 gtk_toggle_button_set_active(
3032 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
3035 gtk_toggle_button_set_active(
3036 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
3037 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
3039 gtk_widget_show_all(dialog);
3041 mapman_update_state(NULL, &mapman_info);
3043 if(_curr_repo->type != REPOTYPE_NONE)
3045 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
3049 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
3051 _("NOTE: You must set a Map URI in the current repository in "
3052 "order to download maps."));
3055 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
3057 MapUpdateType update_type;
3058 static gint8 download_batch_id = INT8_MIN;
3060 if(gtk_toggle_button_get_active(
3061 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
3062 update_type = MAP_UPDATE_DELETE;
3063 else if(gtk_toggle_button_get_active(
3064 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
3065 update_type = MAP_UPDATE_OVERWRITE;
3067 update_type = MAP_UPDATE_ADD;
3069 ++download_batch_id;
3070 if(gtk_toggle_button_get_active(
3071 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
3073 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
3080 gdouble start_lat, start_lon, end_lat, end_lon;
3082 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
3083 start_lat = strdmstod(text, &error_check);
3084 if(text == error_check || start_lat < -90. || start_lat > 90.) {
3085 popup_error(dialog, _("Invalid Top-Left Latitude"));
3089 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
3090 start_lon = strdmstod(text, &error_check);
3091 if(text == error_check || start_lon < -180. || start_lon>180.) {
3092 popup_error(dialog, _("Invalid Top-Left Longitude"));
3096 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
3097 end_lat = strdmstod(text, &error_check);
3098 if(text == error_check || end_lat < -90. || end_lat > 90.) {
3099 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
3103 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
3104 end_lon = strdmstod(text, &error_check);
3105 if(text == error_check || end_lon < -180. || end_lon > 180.) {
3106 popup_error(dialog,_("Invalid Bottom-Right Longitude"));
3110 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
3111 &mapman_info, update_type, download_batch_id))
3116 gtk_widget_hide(dialog);
3118 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);