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, "%0s"))
902 repo->type = REPOTYPE_QUAD_ZERO;
904 repo->type = REPOTYPE_XYZ;
909 repo->type = REPOTYPE_NONE;
911 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
914 /* Returns the directory containing the given database filename, or NULL
915 * if the database file could not be created. */
917 repo_make_db(RepoData *rd)
919 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
923 db_dirname = g_path_get_dirname(rd->db_filename);
925 /* Check if db_filename is a directory and ask to upgrade. */
926 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
928 gchar buffer[BUFFER_SIZE];
929 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
930 g_free(rd->db_filename);
931 rd->db_filename = new_name;
933 snprintf(buffer, sizeof(buffer), "%s",
934 _("The current repository is in a legacy format and will "
935 "be converted. You should delete your old maps if you "
936 "no longer plan to use them."));
937 popup_error(_window, buffer);
940 if(g_mkdir_with_parents(db_dirname, 0755))
947 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
949 fd = g_creat(rd->db_filename, 0644);
958 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
959 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
960 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
964 repo_set_curr(RepoData *rd)
966 printf("%s()\n", __PRETTY_FUNCTION__);
967 if(!rd->db_filename || !*rd->db_filename
974 g_mutex_lock(_mapdb_mutex);
976 sqlite3_close(_curr_repo->db);
978 gdbm_close(_curr_repo->db);
980 _curr_repo->db = NULL;
981 g_mutex_unlock(_mapdb_mutex);
985 /* Set the current repository! */
988 /* Set up the database. */
989 if(_curr_repo->db_filename && *_curr_repo->db_filename)
993 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
995 /* Open worked. Now create tables, failing if they already exist.*/
996 || (sqlite3_exec(_curr_repo->db,
997 "create table maps ("
1002 "primary key (zoom, tilex, tiley))"
1004 "create table dups ("
1005 "hash integer primary key, "
1008 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
1009 /* Prepare select map statement. */
1010 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1011 "select pixbuf from maps "
1012 "where zoom = ? and tilex = ? and tiley = ?",
1013 -1, &_curr_repo->stmt_map_select, NULL)
1014 /* Prepare exists map statement. */
1015 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1016 "select count(*) from maps "
1017 "where zoom = ? and tilex = ? and tiley = ?",
1018 -1, &_curr_repo->stmt_map_exists, NULL)
1019 /* Prepare insert map statement. */
1020 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1021 "insert into maps (pixbuf, zoom, tilex, tiley)"
1022 " values (?, ?, ?, ?)",
1023 -1, &_curr_repo->stmt_map_insert, NULL)
1024 /* Prepare update map statement. */
1025 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1026 "update maps set pixbuf = ? "
1027 "where zoom = ? and tilex = ? and tiley = ?",
1028 -1, &_curr_repo->stmt_map_update, NULL)
1029 /* Prepare delete map statement. */
1030 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1032 "where zoom = ? and tilex = ? and tiley = ?",
1033 -1, &_curr_repo->stmt_map_delete, NULL)
1035 /* Prepare select-by-map dup statement. */
1036 /* Prepare select-by-hash dup statement. */
1037 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1038 "select pixbuf from dups "
1040 -1, &_curr_repo->stmt_dup_select, NULL)
1041 /* Prepare exists map statement. */
1042 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1043 "select count(*) from dups "
1045 -1, &_curr_repo->stmt_dup_exists, NULL)
1046 /* Prepare insert dup statement. */
1047 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1048 "insert into dups (hash, pixbuf, uses) "
1050 -1, &_curr_repo->stmt_dup_insert, NULL)
1051 /* Prepare increment dup statement. */
1052 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1054 "set uses = uses + 1 "
1056 -1, &_curr_repo->stmt_dup_increm, NULL)
1057 /* Prepare decrement dup statement. */
1058 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1060 "set uses = uses - 1 "
1062 -1, &_curr_repo->stmt_dup_decrem, NULL)
1063 /* Prepare delete dup statement. */
1064 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1066 "where hash = ? and uses <= 0",
1067 -1, &_curr_repo->stmt_dup_delete, NULL)
1069 /* Prepare begin-transaction statement. */
1070 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1071 "begin transaction",
1072 -1, &_curr_repo->stmt_trans_begin, NULL)
1073 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1074 "commit transaction",
1075 -1, &_curr_repo->stmt_trans_commit, NULL)
1076 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1077 "rollback transaction", -1,
1078 &_curr_repo->stmt_trans_rollback, NULL))
1080 gchar buffer[BUFFER_SIZE];
1081 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
1082 _("Failed to open map database for repository"),
1083 sqlite3_errmsg(_curr_repo->db),
1084 _("Downloaded maps will not be cached."));
1085 sqlite3_close(_curr_repo->db);
1086 _curr_repo->db = NULL;
1087 popup_error(_window, buffer);
1090 _curr_repo->db = gdbm_open(_curr_repo->db_filename,
1091 0, GDBM_WRCREAT, 0644, NULL);
1094 gchar buffer[BUFFER_SIZE];
1095 snprintf(buffer, sizeof(buffer), "%s\n%s",
1096 _("Failed to open map database for repository"),
1097 _("Downloaded maps will not be cached."));
1098 _curr_repo->db = NULL;
1099 popup_error(_window, buffer);
1105 _curr_repo->db = NULL;
1107 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1112 gchar buffer[BUFFER_SIZE];
1113 snprintf(buffer, sizeof(buffer), "%s: %s",
1114 _("Unable to create map database for repository"), rd->name);
1115 popup_error(_window, buffer);
1117 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1123 * Given a wms uri pattern, compute the coordinate transformation and
1125 * 'proj' is used for the conversion
1128 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
1130 gint system_retcode;
1131 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
1134 gdouble lon1, lat1, lon2, lat2;
1136 gchar *widthstr = strcasestr(uri,"WIDTH=");
1137 gchar *heightstr = strcasestr(uri,"HEIGHT=");
1138 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
1139 gchar *srsstre = strchr(srsstr,'&');
1140 vprintf("%s()\n", __PRETTY_FUNCTION__);
1142 /* missing: test if found */
1144 strncpy(srs+4,srsstr+8,256);
1145 /* missing: test srsstre-srsstr < 526 */
1146 srs[srsstre-srsstr-4] = 0;
1147 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
1149 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
1150 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
1152 unit2latlon(tile2zunit(tilex,zoomlevel)
1153 - pixel2zunit(dwidth/2,zoomlevel),
1154 tile2zunit(tiley+1,zoomlevel)
1155 + pixel2zunit((dheight+1)/2,zoomlevel),
1158 unit2latlon(tile2zunit(tilex+1,zoomlevel)
1159 + pixel2zunit((dwidth+1)/2,zoomlevel),
1160 tile2zunit(tiley,zoomlevel)
1161 - pixel2zunit(dheight/2,zoomlevel),
1164 setlocale(LC_NUMERIC, "C");
1166 snprintf(cmd, sizeof(cmd),
1167 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
1168 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
1169 " > /tmp/tmpcs2cs ",
1170 lon1, lat1, lon2, lat2, srs);
1171 vprintf("Running command: %s\n", cmd);
1172 system_retcode = system(cmd);
1175 g_printerr("cs2cs returned error code %d\n",
1176 WEXITSTATUS(system_retcode));
1177 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
1178 g_printerr("Cannot open results of conversion\n");
1179 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
1180 &lon1, &lat1, cmd, &lon2, &lat2))
1182 g_printerr("Wrong conversion\n");
1188 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
1191 setlocale(LC_NUMERIC, "");
1193 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
1199 * Given the xyz coordinates of our map coordinate system, write the qrst
1200 * quadtree coordinates to buffer.
1203 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
1204 gchar *buffer, const gchar initial,
1205 const gchar *const quadrant)
1207 gchar *ptr = buffer;
1209 vprintf("%s()\n", __PRETTY_FUNCTION__);
1214 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
1216 gint xbit = (x >> n) & 1;
1217 gint ybit = (y >> n) & 1;
1218 *ptr++ = quadrant[xbit + 2 * ybit];
1221 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1225 * Construct the URL that we should fetch, based on the current URI format.
1226 * This method works differently depending on if a "%s" string is present in
1227 * the URI format, since that would indicate a quadtree-based map coordinate
1231 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
1234 vprintf("%s()\n", __PRETTY_FUNCTION__);
1238 retval = g_strdup_printf(repo->url,
1239 tilex, tiley, zoom - (MAX_ZOOM - 16));
1242 case REPOTYPE_XYZ_INV:
1243 retval = g_strdup_printf(repo->url,
1244 MAX_ZOOM + 1 - zoom, tilex, tiley);
1247 case REPOTYPE_QUAD_QRST:
1249 gchar location[MAX_ZOOM + 2];
1250 map_convert_coords_to_quadtree_string(
1251 tilex, tiley, zoom, location, 't', "qrts");
1252 retval = g_strdup_printf(repo->url, location);
1256 case REPOTYPE_QUAD_ZERO:
1258 /* This is a zero-based quadtree URI. */
1259 gchar location[MAX_ZOOM + 2];
1260 map_convert_coords_to_quadtree_string(
1261 tilex, tiley, zoom, location, '\0', "0123");
1262 retval = g_strdup_printf(repo->url, location);
1267 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
1271 retval = g_strdup(repo->url);
1274 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
1279 mapdb_initiate_update_banner_idle()
1281 if(!_download_banner && _num_downloads != _curr_download)
1283 _download_banner = hildon_banner_show_progress(
1284 _window, NULL, _("Processing Maps"));
1285 /* If we're not connected, then hide the banner immediately. It will
1286 * be unhidden if/when we're connected. */
1287 if(!_conic_is_connected)
1288 gtk_widget_hide(_download_banner);
1294 * Initiate a download of the given xyz coordinates using the given buffer
1295 * as the URL. If the map already exists on disk, or if we are already
1296 * downloading the map, then this method does nothing.
1299 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
1300 gint update_type, gint batch_id, gint priority,
1301 ThreadLatch *refresh_latch)
1304 MapUpdateTask *old_mut;
1305 gboolean is_replacing = FALSE;
1306 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1307 repo->name, zoom, tilex, tiley, update_type);
1309 mut = g_slice_new(MapUpdateTask);
1312 /* Could not allocate memory. */
1313 g_printerr("Out of memory in allocation of update task #%d\n",
1314 _num_downloads + 1);
1320 mut->update_type = update_type;
1322 /* Lock the mutex if this is an auto-update. */
1323 if(update_type == MAP_UPDATE_AUTO)
1324 g_mutex_lock(_mut_priority_mutex);
1325 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
1327 /* Check if new mut is in a newer batch that the old mut.
1328 * We use vfs_result to indicate a MUT that is already in the process
1329 * of being downloaded. */
1330 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
1332 /* It is, so remove the old one so we can re-add this one. */
1333 g_hash_table_remove(_mut_exists_table, old_mut);
1334 g_tree_remove(_mut_priority_tree, old_mut);
1335 g_slice_free(MapUpdateTask, old_mut);
1336 is_replacing = TRUE;
1340 /* It's not, so just ignore it. */
1341 if(update_type == MAP_UPDATE_AUTO)
1342 g_mutex_unlock(_mut_priority_mutex);
1343 g_slice_free(MapUpdateTask, mut);
1344 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
1349 g_hash_table_insert(_mut_exists_table, mut, mut);
1352 mut->refresh_latch = refresh_latch;
1353 mut->priority = priority;
1354 mut->batch_id = batch_id;
1356 mut->vfs_result = -1;
1358 g_tree_insert(_mut_priority_tree, mut, mut);
1360 /* Unlock the mutex if this is an auto-update. */
1361 if(update_type == MAP_UPDATE_AUTO)
1362 g_mutex_unlock(_mut_priority_mutex);
1366 /* Increment download count and (possibly) display banner. */
1367 if(++_num_downloads == 20 && !_download_banner)
1368 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
1370 /* This doesn't need to be thread-safe. Extras in the pool don't
1371 * really make a difference. */
1372 if(g_thread_pool_get_num_threads(_mut_thread_pool)
1373 < g_thread_pool_get_max_threads(_mut_thread_pool))
1374 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1377 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1382 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1391 printf("%s()\n", __PRETTY_FUNCTION__);
1393 /* Make sure things are inititalized. */
1396 while(conic_ensure_connected())
1399 gboolean refresh_sent = FALSE;
1400 MapUpdateTask *mut = NULL;
1402 /* Get the next MUT from the mut tree. */
1403 g_mutex_lock(_mut_priority_mutex);
1404 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1407 /* No more MUTs to process. Return. */
1408 g_mutex_unlock(_mut_priority_mutex);
1411 /* Mark this MUT as "in-progress". */
1412 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1413 g_tree_remove(_mut_priority_tree, mut);
1414 g_mutex_unlock(_mut_priority_mutex);
1416 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1417 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1419 if(mut->repo != _curr_repo)
1421 /* Do nothing, except report that there is no error. */
1422 mut->vfs_result = GNOME_VFS_OK;
1424 else if(mut->update_type == MAP_UPDATE_DELETE)
1426 /* Easy - just delete the entry from the database. We don't care
1427 * about failures (sorry). */
1429 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1431 /* Report that there is no error. */
1432 mut->vfs_result = GNOME_VFS_OK;
1434 else for(retries = INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1436 gboolean exists = FALSE;
1440 GdkPixbufLoader *loader;
1442 gint zoom, tilex, tiley;
1443 GError *error = NULL;
1446 /* First check for existence. */
1447 exists = mut->repo->db
1448 ? mapdb_exists(mut->repo, mut->zoom,
1449 mut->tilex, mut->tiley)
1451 if(exists && mut->update_type == MAP_UPDATE_ADD)
1453 /* Map already exists, and we're not going to overwrite. */
1454 /* Report that there is no error. */
1455 mut->vfs_result = GNOME_VFS_OK;
1459 /* First check for existence. */
1460 if(mut->update_type == MAP_UPDATE_ADD)
1462 /* We don't want to overwrite, so check for existence. */
1463 /* Map already exists, and we're not going to overwrite. */
1464 if(mapdb_exists(mut->repo, mut->zoom,
1465 mut->tilex,mut->tiley))
1467 /* Report that there is no error. */
1468 mut->vfs_result = GNOME_VFS_OK;
1474 /* First, construct the URL from which we will get the data. */
1475 src_url = map_construct_url(mut->repo, mut->zoom,
1476 mut->tilex, mut->tiley);
1478 /* Now, attempt to read the entire contents of the URL. */
1479 mut->vfs_result = gnome_vfs_read_entire_file(
1480 src_url, &size, &bytes);
1482 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1485 printf("Error reading URL: %s\n",
1486 gnome_vfs_result_to_string(mut->vfs_result));
1490 /* usleep(100000); DEBUG */
1492 /* Attempt to parse the bytes into a pixbuf. */
1493 loader = gdk_pixbuf_loader_new();
1494 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1495 gdk_pixbuf_loader_close(loader, &error);
1496 if(error || (NULL == (mut->pixbuf = g_object_ref(
1497 gdk_pixbuf_loader_get_pixbuf(loader)))))
1499 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1501 g_object_unref(mut->pixbuf);
1504 g_object_unref(loader);
1505 printf("Error parsing pixbuf: %s\n",
1506 error ? error->message : "?");
1509 g_object_unref(loader);
1511 /* Copy database-relevant mut data before we release it. */
1517 /* Pass the mut to the GTK thread for redrawing, but only if a
1518 * redraw isn't already in the pipeline. */
1519 if(mut->refresh_latch)
1521 /* Wait until the latch is open. */
1522 g_mutex_lock(mut->refresh_latch->mutex);
1523 while(!mut->refresh_latch->is_open)
1525 g_cond_wait(mut->refresh_latch->cond,
1526 mut->refresh_latch->mutex);
1528 /* Latch is open. Decrement the number of waiters and
1529 * check if we're the last waiter to run. */
1530 if(mut->refresh_latch->is_done_adding_tasks)
1532 if(++mut->refresh_latch->num_done
1533 == mut->refresh_latch->num_tasks)
1535 /* Last waiter. Free the latch resources. */
1536 g_mutex_unlock(mut->refresh_latch->mutex);
1537 g_cond_free(mut->refresh_latch->cond);
1538 g_mutex_free(mut->refresh_latch->mutex);
1539 g_slice_free(ThreadLatch, mut->refresh_latch);
1540 mut->refresh_latch = NULL;
1544 /* Not the last waiter. Signal the next waiter.*/
1545 g_cond_signal(mut->refresh_latch->cond);
1546 g_mutex_unlock(mut->refresh_latch->mutex);
1550 g_mutex_unlock(mut->refresh_latch->mutex);
1553 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1554 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1555 refresh_sent = TRUE;
1557 /* DO NOT USE mut FROM THIS POINT ON. */
1559 /* Also attempt to add to the database. */
1560 mapdb_update(exists, repo, zoom,
1561 tilex, tiley, bytes, size);
1569 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1570 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1573 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1578 mut_exists_hashfunc(const MapUpdateTask *a)
1580 gint sum = a->zoom + a->tilex + a->tiley + a->update_type;
1581 return g_int_hash(&sum);
1585 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1587 return (a->tilex == b->tilex
1588 && a->tiley == b->tiley
1589 && a->zoom == b->zoom
1590 && a->update_type == b->update_type);
1594 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1596 /* The update_type enum is sorted in order of ascending priority. */
1597 gint diff = (b->update_type - a->update_type);
1600 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1603 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1607 /* At this point, we don't care, so just pick arbitrarily. */
1608 diff = (a->tilex - b->tilex);
1611 diff = (a->tiley - b->tiley);
1614 return (a->zoom - b->zoom);
1618 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1620 printf("%s()\n", __PRETTY_FUNCTION__);
1621 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1622 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1623 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1628 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1632 printf("%s()\n", __PRETTY_FUNCTION__);
1634 dialog = GTK_WIDGET(
1635 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1636 GTK_FILE_CHOOSER_ACTION_SAVE));
1638 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1639 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1641 /* Work around a bug in HildonFileChooserDialog. */
1642 basename = g_path_get_basename(
1643 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1644 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1645 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1647 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1649 gchar *filename = gtk_file_chooser_get_filename(
1650 GTK_FILE_CHOOSER(dialog));
1651 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1655 gtk_widget_destroy(dialog);
1657 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1662 repoman_compact_complete_idle(CompactInfo *ci)
1664 printf("%s()\n", __PRETTY_FUNCTION__);
1666 gtk_widget_destroy(GTK_WIDGET(ci->banner));
1667 popup_error(ci->dialog, ci->status_msg);
1668 gtk_widget_destroy(ci->dialog);
1671 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1676 thread_repoman_compact(CompactInfo *ci)
1679 printf("%s()\n", __PRETTY_FUNCTION__);
1681 if(!(db = gdbm_open((gchar*)ci->db_filename, 0, GDBM_WRITER | GDBM_FAST,
1683 ci->status_msg = _("Failed to open map database for compacting.");
1686 if(gdbm_reorganize(db))
1687 ci->status_msg = _("An error occurred while trying to "
1688 "compact the database.");
1690 ci->status_msg = _("Successfully compacted database.");
1694 g_idle_add((GSourceFunc)repoman_compact_complete_idle, ci);
1696 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1700 repoman_dialog_compact(GtkWidget *widget, BrowseInfo *browse_info)
1704 printf("%s()\n", __PRETTY_FUNCTION__);
1706 ci = g_new0(CompactInfo, 1);
1708 ci->dialog = gtk_dialog_new_with_buttons(_("Compact Database"),
1709 GTK_WINDOW(browse_info->dialog), GTK_DIALOG_MODAL,
1710 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1711 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1714 sw = gtk_scrolled_window_new (NULL, NULL);
1715 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
1716 GTK_SHADOW_ETCHED_IN);
1717 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
1720 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(ci->dialog)->vbox),
1723 gtk_container_add(GTK_CONTAINER(sw), ci->txt = gtk_text_view_new());
1724 gtk_text_view_set_editable(GTK_TEXT_VIEW(ci->txt), FALSE);
1725 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ci->txt), FALSE);
1726 gtk_text_buffer_set_text(
1727 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1728 _("Generally, deleted maps create an empty space in the "
1729 "database that is later reused when downloading new maps. "
1730 "Compacting the database reorganizes it such that all "
1731 "that blank space is eliminated. This is the only way "
1732 "that the size of the database can decrease.\n"
1733 "This reorganization requires creating a new file and "
1734 "inserting all the maps in the old database file into the "
1735 "new file. The new file is then renamed to the same name "
1736 "as the old file and dbf is updated to contain all the "
1737 "correct information about the new file. Note that this "
1738 "can require free space on disk of an amount up to the size "
1739 "of the map database.\n"
1740 "This process may take several minutes, especially if "
1741 "your map database is large. As a rough estimate, you can "
1742 "expect to wait approximately 2-5 seconds per megabyte of "
1743 "map data (34-85 minutes per gigabyte). There is no progress "
1744 "indicator, although you can watch the new file grow in any "
1745 "file manager. Do not attempt to close Maemo Mapper while "
1746 "the compacting operation is in progress."),
1750 gtk_text_buffer_get_iter_at_offset(
1751 gtk_text_view_get_buffer(GTK_TEXT_VIEW(ci->txt)),
1753 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(ci->txt),
1754 &iter, 0.0, FALSE, 0, 0);
1757 gtk_widget_set_size_request(GTK_WIDGET(sw), 600, 200);
1758 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(ci->txt), GTK_WRAP_WORD);
1760 gtk_widget_show_all(ci->dialog);
1762 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(ci->dialog)))
1764 gtk_widget_set_sensitive(GTK_DIALOG(ci->dialog)->action_area, FALSE);
1765 ci->db_filename = gtk_entry_get_text(GTK_ENTRY(browse_info->txt));
1766 ci->banner = hildon_banner_show_animation(ci->dialog, NULL,
1767 _("Compacting database..."));
1769 g_thread_create((GThreadFunc)thread_repoman_compact, ci, FALSE, NULL);
1773 gtk_widget_destroy(ci->dialog);
1776 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1780 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1782 static GtkWidget *hbox = NULL;
1783 static GtkWidget *label = NULL;
1784 static GtkWidget *txt_name = NULL;
1785 static GtkWidget *dialog = NULL;
1786 printf("%s()\n", __PRETTY_FUNCTION__);
1790 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1791 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1792 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1793 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1796 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1797 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1799 gtk_box_pack_start(GTK_BOX(hbox),
1800 label = gtk_label_new(_("Name")),
1802 gtk_box_pack_start(GTK_BOX(hbox),
1803 txt_name = gtk_entry_new(),
1808 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1809 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1810 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1813 gtk_widget_show_all(dialog);
1815 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1817 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1818 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1820 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1821 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1822 active, g_strdup(rei->name));
1823 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1824 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1828 gtk_widget_hide(dialog);
1830 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1835 repoman_delete(RepoManInfo *rmi, gint index)
1837 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1838 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1839 rmi->repo_edits = g_list_remove_link(
1841 g_list_nth(rmi->repo_edits, index));
1845 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1849 printf("%s()\n", __PRETTY_FUNCTION__);
1851 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1852 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1855 popup_error(rmi->dialog,
1856 _("Cannot delete the last repository - there must be at"
1857 " lease one repository."));
1858 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1862 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1863 _("Confirm delete of repository"),
1864 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1866 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1868 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1870 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1871 repoman_delete(rmi, active);
1872 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1876 gtk_widget_destroy(confirm);
1881 static RepoEditInfo*
1882 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
1888 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
1889 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
1894 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
1895 vbox = gtk_vbox_new(FALSE, 4),
1896 gtk_label_new(name));
1898 /* Prevent destruction of notebook page, because the destruction causes
1899 * a seg fault (!?!?) */
1900 gtk_object_ref(GTK_OBJECT(vbox));
1902 gtk_box_pack_start(GTK_BOX(vbox),
1903 table = gtk_table_new(2, 2, FALSE),
1905 /* Map download URI. */
1906 gtk_table_attach(GTK_TABLE(table),
1907 label = gtk_label_new(_("URL Format")),
1908 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1909 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1910 gtk_table_attach(GTK_TABLE(table),
1911 rei->txt_url = gtk_entry_new(),
1912 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1914 /* Map Directory. */
1915 gtk_table_attach(GTK_TABLE(table),
1916 label = gtk_label_new(_("Cache DB")),
1917 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1918 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1919 gtk_table_attach(GTK_TABLE(table),
1920 hbox = gtk_hbox_new(FALSE, 4),
1921 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1922 gtk_box_pack_start(GTK_BOX(hbox),
1923 rei->txt_db_filename = gtk_entry_new(),
1925 gtk_box_pack_start(GTK_BOX(hbox),
1926 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
1928 gtk_box_pack_start(GTK_BOX(hbox),
1929 rei->btn_compact = gtk_button_new_with_label(_("Compact...")),
1932 /* Initialize cache dir */
1934 gchar buffer[BUFFER_SIZE];
1935 snprintf(buffer, sizeof(buffer), "%s.db", name);
1936 gchar *db_base = gnome_vfs_expand_initial_tilde(
1937 REPO_DEFAULT_CACHE_BASE);
1938 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
1940 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
1941 g_free(db_filename);
1945 gtk_box_pack_start(GTK_BOX(vbox),
1946 table = gtk_table_new(3, 2, FALSE),
1949 /* Download Zoom Steps. */
1950 gtk_table_attach(GTK_TABLE(table),
1951 label = gtk_label_new(_("Download Zoom Steps")),
1952 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1953 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1954 gtk_table_attach(GTK_TABLE(table),
1955 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1956 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1957 gtk_container_add(GTK_CONTAINER(label),
1958 rei->num_dl_zoom_steps = hildon_controlbar_new());
1959 hildon_controlbar_set_range(
1960 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
1961 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1962 REPO_DEFAULT_DL_ZOOM_STEPS);
1963 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
1965 /* Download Zoom Steps. */
1966 gtk_table_attach(GTK_TABLE(table),
1967 label = gtk_label_new(_("View Zoom Steps")),
1968 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1969 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1970 gtk_table_attach(GTK_TABLE(table),
1971 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1972 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
1973 gtk_container_add(GTK_CONTAINER(label),
1974 rei->num_view_zoom_steps = hildon_controlbar_new());
1975 hildon_controlbar_set_range(
1976 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
1977 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1978 REPO_DEFAULT_VIEW_ZOOM_STEPS);
1979 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
1981 gtk_table_attach(GTK_TABLE(table),
1982 label = gtk_vseparator_new(),
1983 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
1986 gtk_table_attach(GTK_TABLE(table),
1987 rei->chk_double_size = gtk_check_button_new_with_label(
1988 _("Double Pixels")),
1989 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1990 gtk_toggle_button_set_active(
1991 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
1994 gtk_table_attach(GTK_TABLE(table),
1995 rei->chk_nextable = gtk_check_button_new_with_label(
1997 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1998 gtk_toggle_button_set_active(
1999 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
2001 /* Downloadable Zoom Levels. */
2002 gtk_table_attach(GTK_TABLE(table),
2003 label = gtk_label_new(_("Downloadable Zooms:")),
2004 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
2005 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2006 gtk_table_attach(GTK_TABLE(table),
2007 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2008 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
2009 gtk_container_add(GTK_CONTAINER(label),
2010 hbox = gtk_hbox_new(FALSE, 4));
2011 gtk_box_pack_start(GTK_BOX(hbox),
2012 label = gtk_label_new(_("Min.")),
2014 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2015 gtk_box_pack_start(GTK_BOX(hbox),
2016 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2018 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
2019 gtk_box_pack_start(GTK_BOX(hbox),
2020 label = gtk_label_new(""),
2022 gtk_box_pack_start(GTK_BOX(hbox),
2023 label = gtk_label_new(_("Max.")),
2025 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2026 gtk_box_pack_start(GTK_BOX(hbox),
2027 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
2029 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
2031 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
2033 /* Connect signals. */
2034 rei->browse_info.dialog = rmi->dialog;
2035 rei->browse_info.txt = rei->txt_db_filename;
2036 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
2037 G_CALLBACK(repoman_dialog_browse),
2039 g_signal_connect(G_OBJECT(rei->btn_compact), "clicked",
2040 G_CALLBACK(repoman_dialog_compact),
2043 gtk_widget_show_all(vbox);
2045 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
2046 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
2047 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
2048 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
2051 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2056 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
2058 static GtkWidget *hbox = NULL;
2059 static GtkWidget *label = NULL;
2060 static GtkWidget *txt_name = NULL;
2061 static GtkWidget *dialog = NULL;
2062 printf("%s()\n", __PRETTY_FUNCTION__);
2066 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
2067 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
2068 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2069 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2072 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2073 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2075 gtk_box_pack_start(GTK_BOX(hbox),
2076 label = gtk_label_new(_("Name")),
2078 gtk_box_pack_start(GTK_BOX(hbox),
2079 txt_name = gtk_entry_new(),
2083 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
2085 gtk_widget_show_all(dialog);
2087 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2089 repoman_dialog_add_repo(rmi,
2090 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
2094 gtk_widget_hide(dialog);
2096 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2101 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
2104 printf("%s()\n", __PRETTY_FUNCTION__);
2106 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
2107 _("Replace all repositories with the default repository?"));
2109 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2111 /* First, delete all existing repositories. */
2112 while(rmi->repo_edits)
2113 repoman_delete(rmi, 0);
2115 /* Now, add the default repository. */
2116 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
2118 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
2119 REPO_DEFAULT_MAP_URI);
2121 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
2123 gtk_widget_destroy(confirm);
2125 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2130 repoman_download(GtkWidget *widget, RepoManInfo *rmi)
2133 printf("%s()\n", __PRETTY_FUNCTION__);
2135 confirm = hildon_note_new_confirmation(
2136 GTK_WINDOW(rmi->dialog),
2137 _("Maemo Mapper will now download and add a list of "
2138 "possibly-duplicate repositories from the internet. "
2141 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2147 GnomeVFSResult vfs_result;
2148 printf("%s()\n", __PRETTY_FUNCTION__);
2150 /* Get repo config file from www.gnuite.com. */
2151 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2152 "http://www.gnuite.com/nokia770/maemo-mapper/repos.txt",
2155 popup_error(rmi->dialog,
2156 _("An error occurred while retrieving the repositories. "
2157 "The web service may be temporarily down."));
2158 g_printerr("Error while download repositories: %s\n",
2159 gnome_vfs_result_to_string(vfs_result));
2161 /* Parse each line as a reposotory. */
2164 for(head = bytes; head && *head; head = tail)
2166 gchar buffer[BUFFER_SIZE];
2169 tail = strchr(head, '\n');
2172 rd = settings_parse_repo(head);
2173 snprintf(buffer, sizeof(buffer), "%s.db", rd->db_filename);
2174 rei = repoman_dialog_add_repo(
2175 rmi, g_strdup(rd->name));
2176 /* Initialize fields with data from the RepoData object. */
2177 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2178 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), buffer);
2179 hildon_controlbar_set_value(
2180 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2182 hildon_controlbar_set_value(
2183 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2184 rd->view_zoom_steps);
2185 gtk_toggle_button_set_active(
2186 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2188 gtk_toggle_button_set_active(
2189 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2191 hildon_number_editor_set_value(
2192 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2194 hildon_number_editor_set_value(
2195 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2201 gtk_widget_destroy(confirm);
2203 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2210 static RepoManInfo rmi;
2211 static GtkWidget *dialog = NULL;
2212 static GtkWidget *hbox = NULL;
2213 static GtkWidget *btn_rename = NULL;
2214 static GtkWidget *btn_delete = NULL;
2215 static GtkWidget *btn_new = NULL;
2216 static GtkWidget *btn_reset = NULL;
2217 static GtkWidget *btn_download = NULL;
2218 gint i, curr_repo_index = 0;
2220 printf("%s()\n", __PRETTY_FUNCTION__);
2224 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
2225 _("Manage Repositories"),
2226 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2227 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2230 /* Enable the help button. */
2232 hildon_help_dialog_help_enable(
2234 ossohelp_dialog_help_enable(
2236 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
2239 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2240 btn_reset = gtk_button_new_with_label(_("Reset...")));
2241 g_signal_connect(G_OBJECT(btn_reset), "clicked",
2242 G_CALLBACK(repoman_reset), &rmi);
2244 /* Download button. */
2245 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2246 btn_download = gtk_button_new_with_label(_("Download...")));
2247 g_signal_connect(G_OBJECT(btn_download), "clicked",
2248 G_CALLBACK(repoman_download), &rmi);
2250 /* Cancel button. */
2251 gtk_dialog_add_button(GTK_DIALOG(dialog),
2252 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2254 hbox = gtk_hbox_new(FALSE, 4);
2256 gtk_box_pack_start(GTK_BOX(hbox),
2257 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
2259 gtk_box_pack_start(GTK_BOX(hbox),
2260 gtk_vseparator_new(), FALSE, FALSE, 4);
2261 gtk_box_pack_start(GTK_BOX(hbox),
2262 btn_rename = gtk_button_new_with_label(_("Rename...")),
2264 gtk_box_pack_start(GTK_BOX(hbox),
2265 btn_delete = gtk_button_new_with_label(_("Delete...")),
2267 gtk_box_pack_start(GTK_BOX(hbox),
2268 btn_new = gtk_button_new_with_label(_("New...")),
2271 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2272 hbox, FALSE, FALSE, 4);
2274 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2275 gtk_hseparator_new(), TRUE, TRUE, 4);
2276 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2277 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
2279 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
2280 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
2282 rmi.repo_edits = NULL;
2284 /* Connect signals. */
2285 g_signal_connect(G_OBJECT(btn_rename), "clicked",
2286 G_CALLBACK(repoman_dialog_rename), &rmi);
2287 g_signal_connect(G_OBJECT(btn_delete), "clicked",
2288 G_CALLBACK(repoman_dialog_delete), &rmi);
2289 g_signal_connect(G_OBJECT(btn_new), "clicked",
2290 G_CALLBACK(repoman_dialog_new), &rmi);
2291 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
2292 G_CALLBACK(repoman_dialog_select), &rmi);
2295 /* Populate combo box and pages in notebook. */
2296 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
2298 RepoData *rd = (RepoData*)curr->data;
2299 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
2301 /* Initialize fields with data from the RepoData object. */
2302 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2303 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
2305 hildon_controlbar_set_value(
2306 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2308 hildon_controlbar_set_value(
2309 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2310 rd->view_zoom_steps);
2311 gtk_toggle_button_set_active(
2312 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2314 gtk_toggle_button_set_active(
2315 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2317 hildon_number_editor_set_value(
2318 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2320 hildon_number_editor_set_value(
2321 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2323 if(rd == _curr_repo)
2324 curr_repo_index = i;
2327 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
2328 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
2330 gtk_widget_show_all(dialog);
2332 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2334 /* Iterate through repos and verify each. */
2335 gboolean verified = TRUE;
2338 gchar *old_curr_repo_name = _curr_repo->name;
2340 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2342 /* Check the ranges for the min and max zoom levels. */
2343 RepoEditInfo *rei = curr->data;
2344 if(hildon_number_editor_get_value(
2345 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
2346 < hildon_number_editor_get_value(
2347 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
2355 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
2357 _("Minimum Downloadable Zoom must be less than "
2358 "Maximum Downloadable Zoom."));
2362 /* We're good to replace. Remove old _repo_list menu items. */
2363 menu_maps_remove_repos();
2364 /* But keep the repo list in memory, in case downloads are using it. */
2367 /* Write new _repo_list. */
2368 curr_repo_index = gtk_combo_box_get_active(
2369 GTK_COMBO_BOX(rmi.cmb_repos));
2371 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2373 RepoEditInfo *rei = curr->data;
2374 RepoData *rd = g_new(RepoData, 1);
2375 rd->name = g_strdup(rei->name);
2376 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
2377 rd->db_filename = gnome_vfs_expand_initial_tilde(
2378 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
2379 rd->dl_zoom_steps = hildon_controlbar_get_value(
2380 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
2381 rd->view_zoom_steps = hildon_controlbar_get_value(
2382 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
2383 rd->double_size = gtk_toggle_button_get_active(
2384 GTK_TOGGLE_BUTTON(rei->chk_double_size));
2385 rd->nextable = gtk_toggle_button_get_active(
2386 GTK_TOGGLE_BUTTON(rei->chk_nextable));
2387 rd->min_zoom = hildon_number_editor_get_value(
2388 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
2389 rd->max_zoom = hildon_number_editor_get_value(
2390 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
2393 _repo_list = g_list_append(_repo_list, rd);
2395 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
2397 else if(i == curr_repo_index)
2401 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
2402 menu_maps_add_repos();
2408 gtk_widget_hide(dialog);
2410 /* Clear out the notebook entries. */
2411 while(rmi.repo_edits)
2412 repoman_delete(&rmi, 0);
2414 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
2416 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2421 mapman_by_area(gdouble start_lat, gdouble start_lon,
2422 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
2423 MapUpdateType update_type,
2424 gint download_batch_id)
2426 gint start_unitx, start_unity, end_unitx, end_unity;
2431 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
2434 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
2435 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
2437 /* Swap if they specified flipped lats or lons. */
2438 if(start_unitx > end_unitx)
2440 gint swap = start_unitx;
2441 start_unitx = end_unitx;
2444 if(start_unity > end_unity)
2446 gint swap = start_unity;
2447 start_unity = end_unity;
2451 /* First, get the number of maps to download. */
2452 for(z = 0; z <= MAX_ZOOM; ++z)
2454 if(gtk_toggle_button_get_active(
2455 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2457 gint start_tilex, start_tiley, end_tilex, end_tiley;
2458 start_tilex = unit2ztile(start_unitx, z);
2459 start_tiley = unit2ztile(start_unity, z);
2460 end_tilex = unit2ztile(end_unitx, z);
2461 end_tiley = unit2ztile(end_unity, z);
2462 num_maps += (end_tilex - start_tilex + 1)
2463 * (end_tiley - start_tiley + 1);
2467 if(update_type == MAP_UPDATE_DELETE)
2469 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
2470 num_maps, _("maps "));
2474 snprintf(buffer, sizeof(buffer),
2475 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2476 num_maps, _("maps"), _("up to about"),
2477 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2479 confirm = hildon_note_new_confirmation(
2480 GTK_WINDOW(mapman_info->dialog), buffer);
2482 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2484 gtk_widget_destroy(confirm);
2485 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2489 g_mutex_lock(_mut_priority_mutex);
2490 for(z = 0; z <= MAX_ZOOM; ++z)
2492 if(gtk_toggle_button_get_active(
2493 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2495 gint start_tilex, start_tiley, end_tilex, end_tiley;
2497 start_tilex = unit2ztile(start_unitx, z);
2498 start_tiley = unit2ztile(start_unity, z);
2499 end_tilex = unit2ztile(end_unitx, z);
2500 end_tiley = unit2ztile(end_unity, z);
2501 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
2503 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
2505 /* Make sure this tile is even possible. */
2506 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
2507 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
2509 mapdb_initiate_update(_curr_repo, z, tilex, tiley,
2510 update_type, download_batch_id,
2511 (abs(tilex - unit2tile(_next_center.unitx))
2512 + abs(tiley - unit2tile(_next_center.unity))),
2519 g_mutex_unlock(_mut_priority_mutex);
2521 gtk_widget_destroy(confirm);
2522 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2527 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
2528 gint download_batch_id)
2531 gint prev_tilex, prev_tiley, num_maps = 0, z;
2534 gint radius = hildon_number_editor_get_value(
2535 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
2536 printf("%s()\n", __PRETTY_FUNCTION__);
2538 /* First, get the number of maps to download. */
2539 for(z = 0; z <= MAX_ZOOM; ++z)
2541 if(gtk_toggle_button_get_active(
2542 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2546 for(curr = _route.head - 1; curr++ != _route.tail; )
2550 gint tilex = unit2ztile(curr->unitx, z);
2551 gint tiley = unit2ztile(curr->unity, z);
2552 if(tilex != prev_tilex || tiley != prev_tiley)
2555 num_maps += (abs((gint)tilex - prev_tilex) + 1)
2556 * (abs((gint)tiley - prev_tiley) + 1) - 1;
2564 num_maps *= 0.625 * pow(radius + 1, 1.85);
2566 if(update_type == MAP_UPDATE_DELETE)
2568 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
2569 _("Confirm DELETION of"), _("about"),
2570 num_maps, _("maps "));
2574 snprintf(buffer, sizeof(buffer),
2575 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2577 num_maps, _("maps"), _("up to about"),
2578 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2580 confirm = hildon_note_new_confirmation(
2581 GTK_WINDOW(mapman_info->dialog), buffer);
2583 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2585 gtk_widget_destroy(confirm);
2586 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2590 /* Now, do the actual download. */
2591 g_mutex_lock(_mut_priority_mutex);
2592 for(z = 0; z <= MAX_ZOOM; ++z)
2594 if(gtk_toggle_button_get_active(
2595 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2599 for(curr = _route.head - 1; curr++ != _route.tail; )
2603 gint tilex = unit2ztile(curr->unitx, z);
2604 gint tiley = unit2ztile(curr->unity, z);
2605 if(tilex != prev_tilex || tiley != prev_tiley)
2607 gint minx, miny, maxx, maxy, x, y;
2610 minx = MIN(tilex, prev_tilex) - radius;
2611 miny = MIN(tiley, prev_tiley) - radius;
2612 maxx = MAX(tilex, prev_tilex) + radius;
2613 maxy = MAX(tiley, prev_tiley) + radius;
2617 minx = tilex - radius;
2618 miny = tiley - radius;
2619 maxx = tilex + radius;
2620 maxy = tiley + radius;
2622 for(x = minx; x <= maxx; x++)
2624 for(y = miny; y <= maxy; y++)
2626 /* Make sure this tile is even possible. */
2628 < unit2ztile(WORLD_SIZE_UNITS, z)
2630 < unit2ztile(WORLD_SIZE_UNITS, z))
2632 mapdb_initiate_update(_curr_repo, z, x, y,
2633 update_type, download_batch_id,
2634 (abs(tilex - unit2tile(
2635 _next_center.unitx))
2636 + abs(tiley - unit2tile(
2637 _next_center.unity))),
2649 g_mutex_unlock(_mut_priority_mutex);
2650 _route_dl_radius = radius;
2651 gtk_widget_destroy(confirm);
2652 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2657 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
2660 printf("%s()\n", __PRETTY_FUNCTION__);
2661 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
2662 /* This is the second page (the "Zoom" page) - clear the checks. */
2663 for(z = 0; z <= MAX_ZOOM; ++z)
2664 gtk_toggle_button_set_active(
2665 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
2668 /* This is the first page (the "Area" page) - clear the text fields. */
2669 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
2670 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
2671 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
2672 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
2674 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2677 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
2679 printf("%s()\n", __PRETTY_FUNCTION__);
2680 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
2681 gtk_toggle_button_get_active(
2682 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
2684 if(gtk_toggle_button_get_active(
2685 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
2686 gtk_widget_show(mapman_info->tbl_area);
2687 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
2688 gtk_widget_hide(mapman_info->tbl_area);
2690 gtk_widget_set_sensitive(mapman_info->num_route_radius,
2691 gtk_toggle_button_get_active(
2692 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
2693 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2699 static GtkWidget *dialog = NULL;
2700 static GtkWidget *vbox = NULL;
2701 static GtkWidget *hbox = NULL;
2702 static GtkWidget *table = NULL;
2703 static GtkWidget *label = NULL;
2704 static GtkWidget *button = NULL;
2705 static GtkWidget *lbl_gps_lat = NULL;
2706 static GtkWidget *lbl_gps_lon = NULL;
2707 static GtkWidget *lbl_center_lat = NULL;
2708 static GtkWidget *lbl_center_lon = NULL;
2709 static MapmanInfo mapman_info;
2713 printf("%s()\n", __PRETTY_FUNCTION__);
2717 popup_error(_window, "To manage maps, you must set a valid repository "
2718 "database filename in the \"Manage Repositories\" dialog.");
2719 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2725 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
2727 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2728 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2731 /* Enable the help button. */
2733 hildon_help_dialog_help_enable(
2735 ossohelp_dialog_help_enable(
2737 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
2740 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2741 button = gtk_button_new_with_label(_("Clear")));
2742 g_signal_connect(G_OBJECT(button), "clicked",
2743 G_CALLBACK(mapman_clear), &mapman_info);
2745 /* Cancel button. */
2746 gtk_dialog_add_button(GTK_DIALOG(dialog),
2747 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2749 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2750 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
2753 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2754 vbox = gtk_vbox_new(FALSE, 2),
2755 label = gtk_label_new(_("Setup")));
2756 gtk_notebook_set_tab_label_packing(
2757 GTK_NOTEBOOK(mapman_info.notebook), vbox,
2758 FALSE, FALSE, GTK_PACK_START);
2760 gtk_box_pack_start(GTK_BOX(vbox),
2761 hbox = gtk_hbox_new(FALSE, 4),
2763 gtk_box_pack_start(GTK_BOX(hbox),
2764 mapman_info.rad_download = gtk_radio_button_new_with_label(
2765 NULL,_("Download Maps")),
2767 gtk_box_pack_start(GTK_BOX(hbox),
2768 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2770 gtk_container_add(GTK_CONTAINER(label),
2771 mapman_info.chk_overwrite
2772 = gtk_check_button_new_with_label(_("Overwrite"))),
2774 gtk_box_pack_start(GTK_BOX(vbox),
2775 mapman_info.rad_delete
2776 = gtk_radio_button_new_with_label_from_widget(
2777 GTK_RADIO_BUTTON(mapman_info.rad_download),
2781 gtk_box_pack_start(GTK_BOX(vbox),
2782 gtk_hseparator_new(),
2785 gtk_box_pack_start(GTK_BOX(vbox),
2786 mapman_info.rad_by_area
2787 = gtk_radio_button_new_with_label(NULL,
2788 _("By Area (see tab)")),
2790 gtk_box_pack_start(GTK_BOX(vbox),
2791 hbox = gtk_hbox_new(FALSE, 4),
2793 gtk_box_pack_start(GTK_BOX(hbox),
2794 mapman_info.rad_by_route
2795 = gtk_radio_button_new_with_label_from_widget(
2796 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
2797 _("Along Route - Radius (tiles):")),
2799 gtk_box_pack_start(GTK_BOX(hbox),
2800 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
2802 hildon_number_editor_set_value(
2803 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
2808 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2809 table = gtk_table_new(5, 5, FALSE),
2810 label = gtk_label_new(_("Zoom")));
2811 gtk_notebook_set_tab_label_packing(
2812 GTK_NOTEBOOK(mapman_info.notebook), table,
2813 FALSE, FALSE, GTK_PACK_START);
2814 gtk_table_attach(GTK_TABLE(table),
2815 label = gtk_label_new(
2816 _("Zoom Levels to Download: (0 = most detail)")),
2817 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
2818 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2819 snprintf(buffer, sizeof(buffer), "%d", 0);
2820 gtk_table_attach(GTK_TABLE(table),
2821 mapman_info.chk_zoom_levels[0]
2822 = gtk_check_button_new_with_label(buffer),
2823 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
2824 for(z = 0; z < MAX_ZOOM; ++z)
2826 snprintf(buffer, sizeof(buffer), "%d", z + 1);
2827 gtk_table_attach(GTK_TABLE(table),
2828 mapman_info.chk_zoom_levels[z + 1]
2829 = gtk_check_button_new_with_label(buffer),
2830 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
2835 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2836 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
2837 label = gtk_label_new(_("Area")));
2839 /* Label Columns. */
2840 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2841 label = gtk_label_new(_("Latitude")),
2842 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
2843 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2844 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2845 label = gtk_label_new(_("Longitude")),
2846 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
2847 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2850 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2851 label = gtk_label_new(_("GPS Location")),
2852 0, 1, 1, 2, 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 lbl_gps_lat = gtk_label_new(""),
2856 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
2857 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
2858 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
2859 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2860 lbl_gps_lon = gtk_label_new(""),
2861 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
2862 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
2863 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
2866 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2867 label = gtk_label_new(_("View Center")),
2868 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
2869 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2870 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2871 lbl_center_lat = gtk_label_new(""),
2872 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
2873 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
2874 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
2875 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2876 lbl_center_lon = gtk_label_new(""),
2877 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
2878 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
2879 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
2881 /* default values for Top Left and Bottom Right are defined by the
2882 * rectangle of the current and the previous Center */
2885 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2886 label = gtk_label_new(_("Top-Left")),
2887 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
2888 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2889 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2890 mapman_info.txt_topleft_lat = gtk_entry_new(),
2891 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
2892 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
2893 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
2894 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2896 "hildon-input-mode",
2897 HILDON_GTK_INPUT_MODE_FULL, NULL);
2899 HILDON_INPUT_MODE_HINT,
2900 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2901 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2905 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2906 mapman_info.txt_topleft_lon = gtk_entry_new(),
2907 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
2908 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
2909 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
2910 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2912 "hildon-input-mode",
2913 HILDON_GTK_INPUT_MODE_FULL, NULL);
2915 HILDON_INPUT_MODE_HINT,
2916 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2917 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2923 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2924 label = gtk_label_new(_("Bottom-Right")),
2925 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
2926 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2927 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2928 mapman_info.txt_botright_lat = gtk_entry_new(),
2929 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
2930 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2931 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
2932 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2934 "hildon-input-mode",
2935 HILDON_GTK_INPUT_MODE_FULL, NULL);
2937 HILDON_INPUT_MODE_HINT,
2938 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2939 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2943 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2944 mapman_info.txt_botright_lon = gtk_entry_new(),
2945 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
2946 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2947 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
2948 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2950 "hildon-input-mode",
2951 HILDON_GTK_INPUT_MODE_FULL, NULL);
2953 HILDON_INPUT_MODE_HINT,
2954 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2955 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2960 /* Default action is to download by area. */
2961 gtk_toggle_button_set_active(
2962 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
2964 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
2965 G_CALLBACK(mapman_update_state), &mapman_info);
2966 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
2967 G_CALLBACK(mapman_update_state), &mapman_info);
2968 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
2969 G_CALLBACK(mapman_update_state), &mapman_info);
2970 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
2971 G_CALLBACK(mapman_update_state), &mapman_info);
2974 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
2975 * output (and parsed) as locale-dependent. */
2977 gtk_widget_set_sensitive(mapman_info.rad_by_route,
2978 _route.head != _route.tail);
2980 lat_format(_gps.lat, buffer);
2981 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
2982 lon_format(_gps.lon, buffer);
2983 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
2985 unit2latlon(_center.unitx, _center.unity, lat, lon);
2986 lat_format(lat, buffer);
2987 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
2988 lon_format(lon, buffer);
2989 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
2991 /* Initialize to the bounds of the screen. */
2993 _center.unitx - pixel2unit(MAX(_view_width_pixels,
2994 _view_height_pixels) / 2),
2995 _center.unity - pixel2unit(MAX(_view_width_pixels,
2996 _view_height_pixels) / 2), lat, lon);
2997 BOUND(lat, -90.f, 90.f);
2998 BOUND(lon, -180.f, 180.f);
2999 lat_format(lat, buffer);
3000 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
3001 lon_format(lon, buffer);
3002 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
3005 _center.unitx + pixel2unit(MAX(_view_width_pixels,
3006 _view_height_pixels) / 2),
3007 _center.unity + pixel2unit(MAX(_view_width_pixels,
3008 _view_height_pixels) / 2), lat, lon);
3009 BOUND(lat, -90.f, 90.f);
3010 BOUND(lon, -180.f, 180.f);
3011 lat_format(lat, buffer);
3012 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
3013 lon_format(lon, buffer);
3014 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
3016 /* Initialize zoom levels. */
3019 for(i = 0; i <= MAX_ZOOM; i++)
3021 gtk_toggle_button_set_active(
3022 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
3025 gtk_toggle_button_set_active(
3026 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
3027 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
3029 gtk_widget_show_all(dialog);
3031 mapman_update_state(NULL, &mapman_info);
3033 if(_curr_repo->type != REPOTYPE_NONE)
3035 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
3039 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
3041 _("NOTE: You must set a Map URI in the current repository in "
3042 "order to download maps."));
3045 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
3047 MapUpdateType update_type;
3048 static gint8 download_batch_id = INT8_MIN;
3050 if(gtk_toggle_button_get_active(
3051 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
3052 update_type = MAP_UPDATE_DELETE;
3053 else if(gtk_toggle_button_get_active(
3054 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
3055 update_type = MAP_UPDATE_OVERWRITE;
3057 update_type = MAP_UPDATE_ADD;
3059 ++download_batch_id;
3060 if(gtk_toggle_button_get_active(
3061 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
3063 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
3070 gdouble start_lat, start_lon, end_lat, end_lon;
3072 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
3073 start_lat = strdmstod(text, &error_check);
3074 if(text == error_check || start_lat < -90. || start_lat > 90.) {
3075 popup_error(dialog, _("Invalid Top-Left Latitude"));
3079 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
3080 start_lon = strdmstod(text, &error_check);
3081 if(text == error_check || start_lon < -180. || start_lon>180.) {
3082 popup_error(dialog, _("Invalid Top-Left Longitude"));
3086 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
3087 end_lat = strdmstod(text, &error_check);
3088 if(text == error_check || end_lat < -90. || end_lat > 90.) {
3089 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
3093 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
3094 end_lon = strdmstod(text, &error_check);
3095 if(text == error_check || end_lon < -180. || end_lon > 180.) {
3096 popup_error(dialog,_("Invalid Bottom-Right Longitude"));
3100 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
3101 &mapman_info, update_type, download_batch_id))
3106 gtk_widget_hide(dialog);
3108 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);