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 *num_min_zoom;
84 GtkWidget *num_max_zoom;
85 BrowseInfo browse_info;
88 typedef struct _MapmanInfo MapmanInfo;
94 /* The "Setup" tab. */
95 GtkWidget *rad_download;
96 GtkWidget *rad_delete;
97 GtkWidget *chk_overwrite;
98 GtkWidget *rad_by_area;
99 GtkWidget *rad_by_route;
100 GtkWidget *num_route_radius;
102 /* The "Area" tab. */
103 GtkWidget *txt_topleft_lat;
104 GtkWidget *txt_topleft_lon;
105 GtkWidget *txt_botright_lat;
106 GtkWidget *txt_botright_lon;
108 /* The "Zoom" tab. */
109 GtkWidget *chk_zoom_levels[MAX_ZOOM + 1];
112 typedef struct _MapCacheKey MapCacheKey;
113 struct _MapCacheKey {
120 typedef struct _MapCacheEntry MapCacheEntry;
121 struct _MapCacheEntry {
132 typedef struct _MapCacheList MapCacheList;
133 struct _MapCacheList {
140 typedef struct _MapCache MapCache;
142 MapCacheList lists[4];
151 static MapCache _map_cache;
155 mapdb_get_data(RepoData *repo, gint zoom, gint tilex, gint tiley, gchar **data)
158 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
159 repo->name, zoom, tilex, tiley);
165 /* There is no cache. Return NULL. */
166 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__,size);
171 /* Attempt to retrieve map from database. */
172 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
173 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
174 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
175 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select))
177 const gchar *bytes = NULL;
178 size = sqlite3_column_bytes(repo->stmt_map_select, 0);
180 /* "Pixbufs" of size less than or equal to MAX_PIXBUF_DUP_SIZE are
181 * actually keys into the dups table. */
182 if(size <= MAX_PIXBUF_DUP_SIZE)
184 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
185 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_select, 1, hash)
186 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_select))
188 bytes = sqlite3_column_blob(repo->stmt_dup_select, 0);
189 size = sqlite3_column_bytes(repo->stmt_dup_select, 0);
193 /* Not there? Delete the entry, then. */
194 if(SQLITE_OK != sqlite3_bind_int(
195 repo->stmt_map_delete, 1, zoom)
196 || SQLITE_OK != sqlite3_bind_int(
197 repo->stmt_map_delete, 2, tilex)
198 || SQLITE_OK != sqlite3_bind_int(
199 repo->stmt_map_delete, 3, tiley)
200 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
202 printf("Error in stmt_map_delete: %s\n",
203 sqlite3_errmsg(repo->db));
205 sqlite3_reset(repo->stmt_map_delete);
207 /* We have no bytes to return to the caller. */
211 /* Don't reset the statement yet - we need the blob. */
215 bytes = sqlite3_column_blob(repo->stmt_map_select, 0);
219 *data = g_slice_alloc(size);
220 memcpy(*data, bytes, size);
222 if(size <= MAX_PIXBUF_DUP_SIZE)
223 sqlite3_reset(repo->stmt_dup_select);
225 sqlite3_reset(repo->stmt_map_select);
234 d.dptr = (gchar*)&key;
235 d.dsize = sizeof(key);
236 d = gdbm_fetch(repo->db, d);
240 *data = g_slice_alloc(size);
241 memcpy(*data, d.dptr, size);
247 vprintf("%s(): return %u\n", __PRETTY_FUNCTION__, size);
251 static void map_cache_list_remove(MapCacheList *_list, MapCacheEntry *_entry)
253 _list->size -= _entry->size;
254 _list->data_sz -= _entry->data_sz;
255 *(_entry->prev != NULL?&_entry->prev->next:&_list->head) = _entry->next;
256 *(_entry->next != NULL?&_entry->next->prev:&_list->tail) = _entry->prev;
259 static void map_cache_list_prepend(MapCacheList *_list, int _li,
260 MapCacheEntry *_entry)
263 _entry->next = _list[_li].head;
264 *(_list[_li].head != NULL?&_list[_li].head->prev:&_list[_li].tail) = _entry;
265 _list[_li].head = _entry;
266 _list[_li].size += _entry->size;
267 _list[_li].data_sz += _entry->data_sz;
271 static guint map_cache_key_hash(gconstpointer _key){
272 const MapCacheKey *key;
273 key = (const MapCacheKey *)_key;
274 return g_direct_hash(key->repo)+g_int_hash(&key->zoom)+
275 g_int_hash(&key->tilex)+g_int_hash(&key->tiley);
278 static gboolean map_cache_key_equal(gconstpointer _v1, gconstpointer _v2){
279 const MapCacheKey *key1;
280 const MapCacheKey *key2;
281 key1 = (const MapCacheKey *)_v1;
282 key2 = (const MapCacheKey *)_v2;
283 return key1->tilex == key2->tilex && key1->tiley == key2->tiley &&
284 key1->zoom == key2->zoom && key1->repo == key2->repo;
287 static void map_cache_entry_make_pixbuf(MapCacheEntry *_entry){
288 if (_entry->data != NULL)
291 GdkPixbufLoader *loader;
293 loader = gdk_pixbuf_loader_new();
294 gdk_pixbuf_loader_write(loader, _entry->data, _entry->data_sz, NULL);
295 gdk_pixbuf_loader_close(loader, &error);
298 _entry->pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
299 _entry->size = _entry->data_sz+
300 gdk_pixbuf_get_rowstride(_entry->pixbuf)*
301 gdk_pixbuf_get_height(_entry->pixbuf);
302 g_object_unref(loader);
305 g_object_unref(loader);
306 g_slice_free1(_entry->data_sz, _entry->data);
310 _entry->pixbuf = NULL;
311 _entry->size = _entry->data_sz;
314 static void map_cache_entry_free_pixbuf(MapCacheEntry *_entry){
315 if(_entry->pixbuf!=NULL)
317 g_object_unref(_entry->pixbuf);
318 _entry->pixbuf = NULL;
322 static void map_cache_entry_free(MapCacheEntry *_entry){
323 if(_entry->list >= 0)
324 map_cache_list_remove(_map_cache.lists+_entry->list, _entry);
325 map_cache_entry_free_pixbuf(_entry);
326 g_slice_free1(_entry->data_sz, _entry->data);
327 g_slice_free(MapCacheEntry, _entry);
331 map_cache_replace(size_t _size, gboolean _b2)
335 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
336 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
338 while(total_size+_size > _map_cache.cache_size)
340 MapCacheEntry *entry;
342 if(_map_cache.lists[0].tail != NULL &&
343 (_map_cache.lists[0].size > _map_cache.p ||
344 (_b2 && _map_cache.lists[0].size == _map_cache.p)))
348 entry = _map_cache.lists[list].tail;
351 map_cache_list_remove(_map_cache.lists+list, entry);
352 map_cache_list_prepend(_map_cache.lists, list+1, entry);
353 total_size -= entry->size - entry->data_sz;
361 map_cache_evict(size_t _size)
365 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
366 +_map_cache.lists[2].size+_map_cache.lists[3].size;
367 max_size = _map_cache.cache_size<<1;
370 if(_map_cache.lists[0].size+_map_cache.lists[1].size+_size >
371 _map_cache.cache_size)
373 if(_map_cache.lists[1].tail != NULL)
375 g_hash_table_remove(_map_cache.entries,
376 &_map_cache.lists[1].tail->key);
377 map_cache_replace(_size, FALSE);
379 else if(_map_cache.lists[0].tail != NULL)
381 g_hash_table_remove(_map_cache.entries,
382 &_map_cache.lists[0].tail->key);
386 else if(total_size+_size > _map_cache.cache_size)
388 if(total_size+_size > max_size &&
389 _map_cache.lists[3].tail != NULL)
391 g_hash_table_remove(_map_cache.entries,
392 &_map_cache.lists[3].tail->key);
393 map_cache_replace(_size, FALSE);
395 else if(!map_cache_replace(_size, FALSE))
399 total_size = _map_cache.lists[0].size+_map_cache.lists[1].size
400 +_map_cache.lists[2].size+_map_cache.lists[3].size;
405 map_cache_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
408 MapCacheEntry *entry;
413 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
416 map_cache_list_remove(_map_cache.lists+entry->list, entry);
417 if(entry->pixbuf == NULL)
421 map_cache_entry_make_pixbuf(entry);
422 bsize = _map_cache.lists[entry->list].size+entry->size;
425 dp = _map_cache.lists[entry->list^2].size/bsize;
431 if(_map_cache.p > _map_cache.cache_size)
432 _map_cache.p = _map_cache.cache_size;
433 map_cache_replace(entry->size, FALSE);
437 if(dp > _map_cache.p)
441 map_cache_replace(entry->size, TRUE);
447 map_cache_list_prepend(_map_cache.lists, 2, entry);
453 data_sz = mapdb_get_data(repo, zoom, tilex, tiley, &data);
454 entry = g_slice_new(MapCacheEntry);
455 *&entry->key = *&key;
457 entry->data_sz = data_sz;
458 map_cache_entry_make_pixbuf(entry);
459 map_cache_evict(entry->size);
460 map_cache_list_prepend(_map_cache.lists, 0, entry);
461 g_hash_table_insert(_map_cache.entries, &entry->key, entry);
464 if(entry->pixbuf != NULL)
465 g_object_ref(entry->pixbuf);
466 return entry->pixbuf;
470 map_cache_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
471 gchar *data,guint size)
474 MapCacheEntry *entry;
479 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
482 g_slice_free1(entry->data_sz, entry->data);
483 entry->data = g_slice_alloc(size);
484 memcpy(entry->data, data, size);
485 entry->data_sz = size;
486 if(entry->pixbuf != NULL)
488 map_cache_entry_free_pixbuf(entry);
489 map_cache_list_remove(_map_cache.lists+entry->list, entry);
490 map_cache_list_prepend(_map_cache.lists, entry->list+1, entry);
496 map_cache_remove(RepoData *repo, gint zoom, gint tilex, gint tiley)
503 g_hash_table_remove(_map_cache.entries, &key);
507 map_cache_init(size_t cache_size)
509 g_mutex_lock(_mapdb_mutex);
510 if(_map_cache.entries == NULL)
511 _map_cache.entries = g_hash_table_new_full(map_cache_key_hash,
512 map_cache_key_equal, NULL, (GDestroyNotify)map_cache_entry_free);
513 _map_cache.cache_size = cache_size;
514 if(_map_cache.p > cache_size)
515 _map_cache.p = cache_size;
517 g_mutex_unlock(_mapdb_mutex);
521 map_cache_resize(size_t cache_size)
524 g_mutex_lock(_mapdb_mutex);
525 _map_cache.cache_size = cache_size;
526 total_size = _map_cache.lists[0].size+_map_cache.lists[1].data_sz
527 +_map_cache.lists[2].size+_map_cache.lists[3].data_sz;
528 g_mutex_unlock(_mapdb_mutex);
533 map_cache_destroy(void)
535 g_mutex_lock(_mapdb_mutex);
536 if(_map_cache.entries != NULL)
538 g_hash_table_destroy(_map_cache.entries);
539 _map_cache.entries = NULL;
540 printf("thits: %u (%0.2f%%) bhits: %u (%0.2f%%) "
541 "misses: %u (%0.2f%%)\n",
542 _map_cache.thits, 100*_map_cache.thits/(double)(
543 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
544 _map_cache.bhits, 100*_map_cache.bhits/(double)(
545 _map_cache.thits+_map_cache.bhits+_map_cache.misses),
546 _map_cache.misses, 100*_map_cache.misses/(double)(
547 _map_cache.thits+_map_cache.bhits+_map_cache.misses));
549 g_mutex_unlock(_mapdb_mutex);
553 mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley)
556 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
557 repo->name, zoom, tilex, tiley);
559 g_mutex_lock(_mapdb_mutex);
563 /* There is no cache. Return FALSE. */
564 g_mutex_unlock(_mapdb_mutex);
565 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
569 /* Search the cache first. */
572 MapCacheEntry *entry;
577 entry = (MapCacheEntry *)g_hash_table_lookup(_map_cache.entries, &key);
581 ret = entry->data != NULL;
582 g_mutex_unlock(_mapdb_mutex);
588 /* Attempt to retrieve map from database. */
589 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom)
590 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex)
591 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley)
592 && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists)
593 && sqlite3_column_int(repo->stmt_map_exists, 0) > 0)
601 sqlite3_reset(repo->stmt_map_exists);
610 d.dptr = (gchar*)&key;
611 d.dsize = sizeof(key);
612 exists = gdbm_exists(repo->db, d);
616 g_mutex_unlock(_mapdb_mutex);
618 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists);
623 mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
626 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
627 repo->name, zoom, tilex, tiley);
628 g_mutex_lock(_mapdb_mutex);
629 pixbuf = map_cache_get(repo, zoom, tilex, tiley);
630 g_mutex_unlock(_mapdb_mutex);
631 vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf);
637 mapdb_checkdec(RepoData *repo, gint zoom, gint tilex, gint tiley)
639 gboolean success = TRUE;
640 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
641 repo->name, zoom, tilex, tiley);
643 /* First, we have to check if the old map was a dup. */
644 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
645 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
646 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
647 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)
648 && sqlite3_column_bytes(repo->stmt_map_select, 0)
649 <= MAX_PIXBUF_DUP_SIZE)
651 /* Old map was indeed a dup. Decrement the reference count. */
652 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
653 if(SQLITE_OK != sqlite3_bind_int(
654 repo->stmt_dup_decrem, 1, hash)
655 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_decrem)
656 || SQLITE_OK != sqlite3_bind_int(
657 repo->stmt_dup_delete, 1, hash)
658 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_delete))
661 printf("Error in stmt_dup_decrem: %s\n",
662 sqlite3_errmsg(repo->db));
664 sqlite3_reset(repo->stmt_dup_delete);
665 sqlite3_reset(repo->stmt_dup_decrem);
667 sqlite3_reset(repo->stmt_map_select);
669 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
675 mapdb_update(gboolean exists, RepoData *repo,
676 gint zoom, gint tilex, gint tiley, void *bytes, gint size)
683 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
684 repo->name, zoom, tilex, tiley);
686 g_mutex_lock(_mapdb_mutex);
687 map_cache_update(repo, zoom, tilex, tiley, bytes, size);
691 /* There is no cache. Return FALSE. */
692 g_mutex_unlock(_mapdb_mutex);
693 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
698 /* At least try to open a transaction. */
699 sqlite3_step(repo->stmt_trans_begin);
700 sqlite3_reset(repo->stmt_trans_begin);
702 /* Pixbufs of size MAX_PIXBUF_DUP_SIZE or less are special. They are
703 * probably PNGs of a single color (like blue for water or beige for empty
704 * land). To reduce redundancy in the database, we will store them in a
705 * separate table and, in the maps table, only refer to them. */
706 if(size <= MAX_PIXBUF_DUP_SIZE)
708 /* Duplicate pixbuf. */
711 /* First, check if we need to remove a count from the dups table.*/
712 mapdb_checkdec(repo, zoom, tilex, tiley);
716 /* Compute hash of the bytes. */
717 gchar *cur = bytes, *end = bytes + size;
720 hash = (hash << 5) - hash + *(++cur);
722 /* Check if dup already exists. */
723 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_exists, 1, hash)
724 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_exists)
725 && sqlite3_column_int(repo->stmt_dup_exists, 0) > 0)
727 /* Dup already exists - increment existing entry. */
728 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_increm,1, hash)
729 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_increm))
732 printf("Error in stmt_dup_increm: %s\n",
733 sqlite3_errmsg(repo->db));
735 sqlite3_reset(repo->stmt_dup_increm);
739 /* Dup doesn't exist - add new entry. */
740 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_insert,1, hash)
741 || SQLITE_OK != sqlite3_bind_blob(repo->stmt_dup_insert,
742 2, bytes, size, NULL)
743 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_insert))
746 printf("Error in stmt_dup_insert: %s\n",
747 sqlite3_errmsg(repo->db));
749 sqlite3_reset(repo->stmt_dup_insert);
751 sqlite3_reset(repo->stmt_dup_exists);
753 /* Now, if successful so far, we fall through the end of this if
754 * statement and insert the hash as the blob. Setting bytes to NULL
755 * is the signal to do this. */
761 stmt = exists ? repo->stmt_map_update : repo->stmt_map_insert;
763 /* Attempt to insert map from database. */
764 if(SQLITE_OK != (bytes ? sqlite3_bind_blob(stmt, 1, bytes, size, NULL)
765 : sqlite3_bind_int(stmt, 1, hash))
766 || SQLITE_OK != sqlite3_bind_int(stmt, 2, zoom)
767 || SQLITE_OK != sqlite3_bind_int(stmt, 3, tilex)
768 || SQLITE_OK != sqlite3_bind_int(stmt, 4, tiley)
769 || SQLITE_DONE != sqlite3_step(stmt))
772 printf("Error in mapdb_update: %s\n", sqlite3_errmsg(repo->db));
779 sqlite3_step(repo->stmt_trans_commit);
780 sqlite3_reset(repo->stmt_trans_commit);
784 sqlite3_step(repo->stmt_trans_rollback);
785 sqlite3_reset(repo->stmt_trans_rollback);
796 dkey.dptr = (gchar*)&key;
797 dkey.dsize = sizeof(key);
800 success = !gdbm_store(repo->db, dkey, dcon, GDBM_REPLACE);
803 g_mutex_unlock(_mapdb_mutex);
805 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
810 mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley)
812 gint success = FALSE;
813 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
814 repo->name, zoom, tilex, tiley);
816 g_mutex_lock(_mapdb_mutex);
817 map_cache_remove(repo, zoom, tilex, tiley);
821 /* There is no cache. Return FALSE. */
822 g_mutex_unlock(_mapdb_mutex);
823 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
828 /* At least try to open a transaction. */
829 sqlite3_step(repo->stmt_trans_begin);
830 sqlite3_reset(repo->stmt_trans_begin);
832 /* First, check if we need to remove a count from the dups table. */
833 /* Then, attempt to delete map from database. */
834 if(!mapdb_checkdec(repo, zoom, tilex, tiley)
835 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 1, zoom)
836 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 2, tilex)
837 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 3, tiley)
838 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
841 printf("Error in stmt_map_delete: %s\n",
842 sqlite3_errmsg(repo->db));
844 sqlite3_reset(repo->stmt_map_delete);
848 sqlite3_step(repo->stmt_trans_commit);
849 sqlite3_reset(repo->stmt_trans_commit);
853 sqlite3_step(repo->stmt_trans_rollback);
854 sqlite3_reset(repo->stmt_trans_rollback);
864 d.dptr = (gchar*)&key;
865 d.dsize = sizeof(key);
866 success = !gdbm_delete(repo->db, d);
869 g_mutex_unlock(_mapdb_mutex);
871 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
876 set_repo_type(RepoData *repo)
878 printf("%s(%s)\n", __PRETTY_FUNCTION__, repo->url);
880 if(repo->url && *repo->url)
882 gchar *url = g_utf8_strdown(repo->url, -1);
884 /* Determine type of repository. */
885 if(strstr(url, "service=wms"))
886 repo->type = REPOTYPE_WMS;
887 else if(strstr(url, "%s"))
888 repo->type = REPOTYPE_QUAD_QRST;
889 else if(strstr(url, "%0d"))
890 repo->type = REPOTYPE_XYZ_INV;
891 else if(strstr(url, "%0s"))
892 repo->type = REPOTYPE_QUAD_ZERO;
894 repo->type = REPOTYPE_XYZ;
899 repo->type = REPOTYPE_NONE;
901 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
904 /* Returns the directory containing the given database filename, or NULL
905 * if the database file could not be created. */
907 repo_make_db(RepoData *rd)
909 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
913 db_dirname = g_path_get_dirname(rd->db_filename);
915 /* Check if db_filename is a directory and ask to upgrade. */
916 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
918 gchar buffer[BUFFER_SIZE];
919 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
920 g_free(rd->db_filename);
921 rd->db_filename = new_name;
923 snprintf(buffer, sizeof(buffer), "%s",
924 _("The current repository is in a legacy format and will "
925 "be converted. You should delete your old maps if you "
926 "no longer plan to use them."));
927 popup_error(_window, buffer);
930 if(g_mkdir_with_parents(db_dirname, 0755))
937 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
939 fd = g_creat(rd->db_filename, 0644);
948 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
949 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
950 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
954 repo_set_curr(RepoData *rd)
956 printf("%s()\n", __PRETTY_FUNCTION__);
957 if(!rd->db_filename || !*rd->db_filename
964 g_mutex_lock(_mapdb_mutex);
966 sqlite3_close(_curr_repo->db);
968 gdbm_close(_curr_repo->db);
970 _curr_repo->db = NULL;
971 g_mutex_unlock(_mapdb_mutex);
975 /* Set the current repository! */
978 /* Set up the database. */
979 if(_curr_repo->db_filename && *_curr_repo->db_filename)
983 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
985 /* Open worked. Now create tables, failing if they already exist.*/
986 || (sqlite3_exec(_curr_repo->db,
987 "create table maps ("
992 "primary key (zoom, tilex, tiley))"
994 "create table dups ("
995 "hash integer primary key, "
998 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
999 /* Prepare select map statement. */
1000 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1001 "select pixbuf from maps "
1002 "where zoom = ? and tilex = ? and tiley = ?",
1003 -1, &_curr_repo->stmt_map_select, NULL)
1004 /* Prepare exists map statement. */
1005 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1006 "select count(*) from maps "
1007 "where zoom = ? and tilex = ? and tiley = ?",
1008 -1, &_curr_repo->stmt_map_exists, NULL)
1009 /* Prepare insert map statement. */
1010 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1011 "insert into maps (pixbuf, zoom, tilex, tiley)"
1012 " values (?, ?, ?, ?)",
1013 -1, &_curr_repo->stmt_map_insert, NULL)
1014 /* Prepare update map statement. */
1015 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1016 "update maps set pixbuf = ? "
1017 "where zoom = ? and tilex = ? and tiley = ?",
1018 -1, &_curr_repo->stmt_map_update, NULL)
1019 /* Prepare delete map statement. */
1020 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1022 "where zoom = ? and tilex = ? and tiley = ?",
1023 -1, &_curr_repo->stmt_map_delete, NULL)
1025 /* Prepare select-by-map dup statement. */
1026 /* Prepare select-by-hash dup statement. */
1027 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1028 "select pixbuf from dups "
1030 -1, &_curr_repo->stmt_dup_select, NULL)
1031 /* Prepare exists map statement. */
1032 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1033 "select count(*) from dups "
1035 -1, &_curr_repo->stmt_dup_exists, NULL)
1036 /* Prepare insert dup statement. */
1037 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1038 "insert into dups (hash, pixbuf, uses) "
1040 -1, &_curr_repo->stmt_dup_insert, NULL)
1041 /* Prepare increment dup statement. */
1042 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1044 "set uses = uses + 1 "
1046 -1, &_curr_repo->stmt_dup_increm, NULL)
1047 /* Prepare decrement dup statement. */
1048 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1050 "set uses = uses - 1 "
1052 -1, &_curr_repo->stmt_dup_decrem, NULL)
1053 /* Prepare delete dup statement. */
1054 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1056 "where hash = ? and uses <= 0",
1057 -1, &_curr_repo->stmt_dup_delete, NULL)
1059 /* Prepare begin-transaction statement. */
1060 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1061 "begin transaction",
1062 -1, &_curr_repo->stmt_trans_begin, NULL)
1063 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1064 "commit transaction",
1065 -1, &_curr_repo->stmt_trans_commit, NULL)
1066 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
1067 "rollback transaction", -1,
1068 &_curr_repo->stmt_trans_rollback, NULL))
1070 gchar buffer[BUFFER_SIZE];
1071 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
1072 _("Failed to open map database for repository"),
1073 sqlite3_errmsg(_curr_repo->db),
1074 _("Downloaded maps will not be cached."));
1075 sqlite3_close(_curr_repo->db);
1076 _curr_repo->db = NULL;
1077 popup_error(_window, buffer);
1080 _curr_repo->db = gdbm_open(_curr_repo->db_filename,
1081 0, GDBM_WRCREAT, 0644, NULL);
1084 gchar buffer[BUFFER_SIZE];
1085 snprintf(buffer, sizeof(buffer), "%s\n%s",
1086 _("Failed to open map database for repository"),
1087 _("Downloaded maps will not be cached."));
1088 _curr_repo->db = NULL;
1089 popup_error(_window, buffer);
1095 _curr_repo->db = NULL;
1097 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1102 gchar buffer[BUFFER_SIZE];
1103 snprintf(buffer, sizeof(buffer), "%s: %s",
1104 _("Unable to create map database for repository"), rd->name);
1105 popup_error(_window, buffer);
1107 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1113 * Given a wms uri pattern, compute the coordinate transformation and
1115 * 'proj' is used for the conversion
1118 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
1120 gint system_retcode;
1121 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
1124 gdouble lon1, lat1, lon2, lat2;
1126 gchar *widthstr = strcasestr(uri,"WIDTH=");
1127 gchar *heightstr = strcasestr(uri,"HEIGHT=");
1128 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
1129 gchar *srsstre = strchr(srsstr,'&');
1130 vprintf("%s()\n", __PRETTY_FUNCTION__);
1132 /* missing: test if found */
1134 strncpy(srs+4,srsstr+8,256);
1135 /* missing: test srsstre-srsstr < 526 */
1136 srs[srsstre-srsstr-4] = 0;
1137 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
1139 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
1140 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
1142 unit2latlon(tile2zunit(tilex,zoomlevel)
1143 - pixel2zunit(dwidth/2,zoomlevel),
1144 tile2zunit(tiley+1,zoomlevel)
1145 + pixel2zunit((dheight+1)/2,zoomlevel),
1148 unit2latlon(tile2zunit(tilex+1,zoomlevel)
1149 + pixel2zunit((dwidth+1)/2,zoomlevel),
1150 tile2zunit(tiley,zoomlevel)
1151 - pixel2zunit(dheight/2,zoomlevel),
1154 setlocale(LC_NUMERIC, "C");
1156 snprintf(cmd, sizeof(cmd),
1157 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
1158 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
1159 " > /tmp/tmpcs2cs ",
1160 lon1, lat1, lon2, lat2, srs);
1161 vprintf("Running command: %s\n", cmd);
1162 system_retcode = system(cmd);
1165 g_printerr("cs2cs returned error code %d\n",
1166 WEXITSTATUS(system_retcode));
1167 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
1168 g_printerr("Cannot open results of conversion\n");
1169 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
1170 &lon1, &lat1, cmd, &lon2, &lat2))
1172 g_printerr("Wrong conversion\n");
1178 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
1181 setlocale(LC_NUMERIC, "");
1183 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
1189 * Given the xyz coordinates of our map coordinate system, write the qrst
1190 * quadtree coordinates to buffer.
1193 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
1194 gchar *buffer, const gchar initial,
1195 const gchar *const quadrant)
1197 gchar *ptr = buffer;
1199 vprintf("%s()\n", __PRETTY_FUNCTION__);
1204 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
1206 gint xbit = (x >> n) & 1;
1207 gint ybit = (y >> n) & 1;
1208 *ptr++ = quadrant[xbit + 2 * ybit];
1211 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1215 * Construct the URL that we should fetch, based on the current URI format.
1216 * This method works differently depending on if a "%s" string is present in
1217 * the URI format, since that would indicate a quadtree-based map coordinate
1221 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
1224 vprintf("%s()\n", __PRETTY_FUNCTION__);
1228 retval = g_strdup_printf(repo->url,
1229 tilex, tiley, zoom - (MAX_ZOOM - 16));
1232 case REPOTYPE_XYZ_INV:
1233 retval = g_strdup_printf(repo->url,
1234 MAX_ZOOM + 1 - zoom, tilex, tiley);
1237 case REPOTYPE_QUAD_QRST:
1239 gchar location[MAX_ZOOM + 2];
1240 map_convert_coords_to_quadtree_string(
1241 tilex, tiley, zoom, location, 't', "qrts");
1242 retval = g_strdup_printf(repo->url, location);
1246 case REPOTYPE_QUAD_ZERO:
1248 /* This is a zero-based quadtree URI. */
1249 gchar location[MAX_ZOOM + 2];
1250 map_convert_coords_to_quadtree_string(
1251 tilex, tiley, zoom, location, '\0', "0123");
1252 retval = g_strdup_printf(repo->url, location);
1257 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
1261 retval = g_strdup(repo->url);
1264 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
1269 mapdb_initiate_update_banner_idle()
1271 if(!_download_banner && _num_downloads != _curr_download)
1273 _download_banner = hildon_banner_show_progress(
1274 _window, NULL, _("Processing Maps"));
1275 /* If we're not connected, then hide the banner immediately. It will
1276 * be unhidden if/when we're connected. */
1277 if(!_conic_is_connected)
1278 gtk_widget_hide(_download_banner);
1284 * Initiate a download of the given xyz coordinates using the given buffer
1285 * as the URL. If the map already exists on disk, or if we are already
1286 * downloading the map, then this method does nothing.
1289 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
1290 gint update_type, gint batch_id, gint priority,
1291 ThreadLatch *refresh_latch)
1294 MapUpdateTask *old_mut;
1295 gboolean is_replacing = FALSE;
1296 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1297 repo->name, zoom, tilex, tiley, update_type);
1299 mut = g_slice_new(MapUpdateTask);
1302 /* Could not allocate memory. */
1303 g_printerr("Out of memory in allocation of update task #%d\n",
1304 _num_downloads + 1);
1310 mut->update_type = update_type;
1312 /* Lock the mutex if this is an auto-update. */
1313 if(update_type == MAP_UPDATE_AUTO)
1314 g_mutex_lock(_mut_priority_mutex);
1315 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
1317 /* Check if new mut is in a newer batch that the old mut.
1318 * We use vfs_result to indicate a MUT that is already in the process
1319 * of being downloaded. */
1320 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
1322 /* It is, so remove the old one so we can re-add this one. */
1323 g_hash_table_remove(_mut_exists_table, old_mut);
1324 g_tree_remove(_mut_priority_tree, old_mut);
1325 g_slice_free(MapUpdateTask, old_mut);
1326 is_replacing = TRUE;
1330 /* It's not, so just ignore it. */
1331 if(update_type == MAP_UPDATE_AUTO)
1332 g_mutex_unlock(_mut_priority_mutex);
1333 g_slice_free(MapUpdateTask, mut);
1334 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
1339 g_hash_table_insert(_mut_exists_table, mut, mut);
1342 mut->refresh_latch = refresh_latch;
1343 mut->priority = priority;
1344 mut->batch_id = batch_id;
1346 mut->vfs_result = -1;
1348 g_tree_insert(_mut_priority_tree, mut, mut);
1350 /* Unlock the mutex if this is an auto-update. */
1351 if(update_type == MAP_UPDATE_AUTO)
1352 g_mutex_unlock(_mut_priority_mutex);
1356 /* Increment download count and (possibly) display banner. */
1357 if(++_num_downloads == 20 && !_download_banner)
1358 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
1360 /* This doesn't need to be thread-safe. Extras in the pool don't
1361 * really make a difference. */
1362 if(g_thread_pool_get_num_threads(_mut_thread_pool)
1363 < g_thread_pool_get_max_threads(_mut_thread_pool))
1364 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1367 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1372 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1381 printf("%s()\n", __PRETTY_FUNCTION__);
1383 /* Make sure things are inititalized. */
1389 gboolean refresh_sent = FALSE;
1390 MapUpdateTask *mut = NULL;
1392 /* Wait until we are connected. */
1393 conic_ensure_connected();
1395 /* Get the next MUT from the mut tree. */
1396 g_mutex_lock(_mut_priority_mutex);
1397 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1400 /* No more MUTs to process. Return. */
1401 g_mutex_unlock(_mut_priority_mutex);
1404 /* Mark this MUT as "in-progress". */
1405 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1406 g_tree_remove(_mut_priority_tree, mut);
1407 g_mutex_unlock(_mut_priority_mutex);
1409 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1410 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1412 if(mut->repo != _curr_repo)
1414 /* Do nothing, except report that there is no error. */
1415 mut->vfs_result = GNOME_VFS_OK;
1417 else if(mut->update_type == MAP_UPDATE_DELETE)
1419 /* Easy - just delete the entry from the database. We don't care
1420 * about failures (sorry). */
1422 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1424 /* Report that there is no error. */
1425 mut->vfs_result = GNOME_VFS_OK;
1427 else for(retries = INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1429 gboolean exists = FALSE;
1433 GdkPixbufLoader *loader;
1435 gint zoom, tilex, tiley;
1436 GError *error = NULL;
1439 /* First check for existence. */
1440 exists = mut->repo->db
1441 ? mapdb_exists(mut->repo, mut->zoom,
1442 mut->tilex, mut->tiley)
1444 if(exists && mut->update_type == MAP_UPDATE_ADD)
1446 /* Map already exists, and we're not going to overwrite. */
1447 /* Report that there is no error. */
1448 mut->vfs_result = GNOME_VFS_OK;
1452 /* First check for existence. */
1453 if(mut->update_type == MAP_UPDATE_ADD)
1455 /* We don't want to overwrite, so check for existence. */
1456 /* Map already exists, and we're not going to overwrite. */
1457 if(mapdb_exists(mut->repo, mut->zoom,
1458 mut->tilex,mut->tiley))
1460 /* Report that there is no error. */
1461 mut->vfs_result = GNOME_VFS_OK;
1467 /* First, construct the URL from which we will get the data. */
1468 src_url = map_construct_url(mut->repo, mut->zoom,
1469 mut->tilex, mut->tiley);
1471 /* Now, attempt to read the entire contents of the URL. */
1472 mut->vfs_result = gnome_vfs_read_entire_file(
1473 src_url, &size, &bytes);
1475 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1478 printf("Error reading URL: %s\n",
1479 gnome_vfs_result_to_string(mut->vfs_result));
1483 /* usleep(100000); DEBUG */
1485 /* Attempt to parse the bytes into a pixbuf. */
1486 loader = gdk_pixbuf_loader_new();
1487 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1488 gdk_pixbuf_loader_close(loader, &error);
1489 if(error || (NULL == (mut->pixbuf = g_object_ref(
1490 gdk_pixbuf_loader_get_pixbuf(loader)))))
1492 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1494 g_object_unref(mut->pixbuf);
1497 g_object_unref(loader);
1498 printf("Error parsing pixbuf: %s\n",
1499 error ? error->message : "?");
1502 g_object_unref(loader);
1504 /* Copy database-relevant mut data before we release it. */
1510 /* Pass the mut to the GTK thread for redrawing, but only if a
1511 * redraw isn't already in the pipeline. */
1512 if(mut->refresh_latch)
1514 /* Wait until the latch is open. */
1515 g_mutex_lock(mut->refresh_latch->mutex);
1516 while(!mut->refresh_latch->is_open)
1518 g_cond_wait(mut->refresh_latch->cond,
1519 mut->refresh_latch->mutex);
1521 /* Latch is open. Decrement the number of waiters and
1522 * check if we're the last waiter to run. */
1523 if(mut->refresh_latch->is_done_adding_tasks)
1525 if(++mut->refresh_latch->num_done
1526 == mut->refresh_latch->num_tasks)
1528 /* Last waiter. Free the latch resources. */
1529 g_mutex_unlock(mut->refresh_latch->mutex);
1530 g_cond_free(mut->refresh_latch->cond);
1531 g_mutex_free(mut->refresh_latch->mutex);
1532 g_slice_free(ThreadLatch, mut->refresh_latch);
1533 mut->refresh_latch = NULL;
1537 /* Not the last waiter. Signal the next waiter.*/
1538 g_cond_signal(mut->refresh_latch->cond);
1539 g_mutex_unlock(mut->refresh_latch->mutex);
1543 g_mutex_unlock(mut->refresh_latch->mutex);
1546 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1547 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1548 refresh_sent = TRUE;
1550 /* DO NOT USE mut FROM THIS POINT ON. */
1552 /* Also attempt to add to the database. */
1553 mapdb_update(exists, repo, zoom,
1554 tilex, tiley, bytes, size);
1562 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1563 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1566 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1571 mut_exists_hashfunc(const MapUpdateTask *a)
1573 gint sum = a->zoom + a->tilex + a->tiley + a->update_type;
1574 return g_int_hash(&sum);
1578 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1580 return (a->tilex == b->tilex
1581 && a->tiley == b->tiley
1582 && a->zoom == b->zoom
1583 && a->update_type == b->update_type);
1587 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1589 /* The update_type enum is sorted in order of ascending priority. */
1590 gint diff = (b->update_type - a->update_type);
1593 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1596 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1600 /* At this point, we don't care, so just pick arbitrarily. */
1601 diff = (a->tilex - b->tilex);
1604 diff = (a->tiley - b->tiley);
1607 return (a->zoom - b->zoom);
1611 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1613 printf("%s()\n", __PRETTY_FUNCTION__);
1614 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1615 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1616 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1621 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1625 printf("%s()\n", __PRETTY_FUNCTION__);
1627 dialog = GTK_WIDGET(
1628 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1629 GTK_FILE_CHOOSER_ACTION_SAVE));
1631 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1632 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1634 /* Work around a bug in HildonFileChooserDialog. */
1635 basename = g_path_get_basename(
1636 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1637 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1638 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1640 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1642 gchar *filename = gtk_file_chooser_get_filename(
1643 GTK_FILE_CHOOSER(dialog));
1644 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1648 gtk_widget_destroy(dialog);
1650 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1655 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1657 static GtkWidget *hbox = NULL;
1658 static GtkWidget *label = NULL;
1659 static GtkWidget *txt_name = NULL;
1660 static GtkWidget *dialog = NULL;
1661 printf("%s()\n", __PRETTY_FUNCTION__);
1665 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1666 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1667 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1668 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1671 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1672 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1674 gtk_box_pack_start(GTK_BOX(hbox),
1675 label = gtk_label_new(_("Name")),
1677 gtk_box_pack_start(GTK_BOX(hbox),
1678 txt_name = gtk_entry_new(),
1683 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1684 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1685 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1688 gtk_widget_show_all(dialog);
1690 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1692 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1693 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1695 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1696 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1697 active, g_strdup(rei->name));
1698 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1699 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1703 gtk_widget_hide(dialog);
1705 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1710 repoman_delete(RepoManInfo *rmi, gint index)
1712 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1713 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1714 rmi->repo_edits = g_list_remove_link(
1716 g_list_nth(rmi->repo_edits, index));
1720 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1724 printf("%s()\n", __PRETTY_FUNCTION__);
1726 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1727 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1730 popup_error(rmi->dialog,
1731 _("Cannot delete the last repository - there must be at"
1732 " lease one repository."));
1733 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1737 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1738 _("Confirm delete of repository"),
1739 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1741 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1743 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1745 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1746 repoman_delete(rmi, active);
1747 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1751 gtk_widget_destroy(confirm);
1756 static RepoEditInfo*
1757 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
1763 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
1764 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
1769 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
1770 vbox = gtk_vbox_new(FALSE, 4),
1771 gtk_label_new(name));
1773 /* Prevent destruction of notebook page, because the destruction causes
1774 * a seg fault (!?!?) */
1775 gtk_object_ref(GTK_OBJECT(vbox));
1777 gtk_box_pack_start(GTK_BOX(vbox),
1778 table = gtk_table_new(2, 2, FALSE),
1780 /* Map download URI. */
1781 gtk_table_attach(GTK_TABLE(table),
1782 label = gtk_label_new(_("URL Format")),
1783 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1784 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1785 gtk_table_attach(GTK_TABLE(table),
1786 rei->txt_url = gtk_entry_new(),
1787 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1789 /* Map Directory. */
1790 gtk_table_attach(GTK_TABLE(table),
1791 label = gtk_label_new(_("Cache DB")),
1792 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1793 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1794 gtk_table_attach(GTK_TABLE(table),
1795 hbox = gtk_hbox_new(FALSE, 4),
1796 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1797 gtk_box_pack_start(GTK_BOX(hbox),
1798 rei->txt_db_filename = gtk_entry_new(),
1800 gtk_box_pack_start(GTK_BOX(hbox),
1801 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
1804 /* Initialize cache dir */
1806 gchar buffer[BUFFER_SIZE];
1807 snprintf(buffer, sizeof(buffer), "%s.db", name);
1808 gchar *db_base = gnome_vfs_expand_initial_tilde(
1809 REPO_DEFAULT_CACHE_BASE);
1810 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
1812 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
1813 g_free(db_filename);
1817 gtk_box_pack_start(GTK_BOX(vbox),
1818 table = gtk_table_new(3, 2, FALSE),
1821 /* Download Zoom Steps. */
1822 gtk_table_attach(GTK_TABLE(table),
1823 label = gtk_label_new(_("Download Zoom Steps")),
1824 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1825 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1826 gtk_table_attach(GTK_TABLE(table),
1827 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1828 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1829 gtk_container_add(GTK_CONTAINER(label),
1830 rei->num_dl_zoom_steps = hildon_controlbar_new());
1831 hildon_controlbar_set_range(
1832 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
1833 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1834 REPO_DEFAULT_DL_ZOOM_STEPS);
1835 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
1837 /* Download Zoom Steps. */
1838 gtk_table_attach(GTK_TABLE(table),
1839 label = gtk_label_new(_("View Zoom Steps")),
1840 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1841 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1842 gtk_table_attach(GTK_TABLE(table),
1843 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1844 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
1845 gtk_container_add(GTK_CONTAINER(label),
1846 rei->num_view_zoom_steps = hildon_controlbar_new());
1847 hildon_controlbar_set_range(
1848 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
1849 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1850 REPO_DEFAULT_VIEW_ZOOM_STEPS);
1851 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
1853 gtk_table_attach(GTK_TABLE(table),
1854 label = gtk_vseparator_new(),
1855 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
1858 gtk_table_attach(GTK_TABLE(table),
1859 rei->chk_double_size = gtk_check_button_new_with_label(
1860 _("Double Pixels")),
1861 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1862 gtk_toggle_button_set_active(
1863 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
1866 gtk_table_attach(GTK_TABLE(table),
1867 rei->chk_nextable = gtk_check_button_new_with_label(
1869 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1870 gtk_toggle_button_set_active(
1871 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
1873 /* Downloadable Zoom Levels. */
1874 gtk_table_attach(GTK_TABLE(table),
1875 label = gtk_label_new(_("Downloadable Zooms:")),
1876 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
1877 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1878 gtk_table_attach(GTK_TABLE(table),
1879 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1880 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
1881 gtk_container_add(GTK_CONTAINER(label),
1882 hbox = gtk_hbox_new(FALSE, 4));
1883 gtk_box_pack_start(GTK_BOX(hbox),
1884 label = gtk_label_new(_("Min.")),
1886 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1887 gtk_box_pack_start(GTK_BOX(hbox),
1888 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
1890 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
1891 gtk_box_pack_start(GTK_BOX(hbox),
1892 label = gtk_label_new(""),
1894 gtk_box_pack_start(GTK_BOX(hbox),
1895 label = gtk_label_new(_("Max.")),
1897 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1898 gtk_box_pack_start(GTK_BOX(hbox),
1899 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
1901 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
1903 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
1905 /* Connect signals. */
1906 rei->browse_info.dialog = rmi->dialog;
1907 rei->browse_info.txt = rei->txt_db_filename;
1908 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
1909 G_CALLBACK(repoman_dialog_browse),
1912 gtk_widget_show_all(vbox);
1914 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
1915 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1916 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1917 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1920 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1925 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
1927 static GtkWidget *hbox = NULL;
1928 static GtkWidget *label = NULL;
1929 static GtkWidget *txt_name = NULL;
1930 static GtkWidget *dialog = NULL;
1931 printf("%s()\n", __PRETTY_FUNCTION__);
1935 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
1936 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1937 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1938 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1941 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1942 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1944 gtk_box_pack_start(GTK_BOX(hbox),
1945 label = gtk_label_new(_("Name")),
1947 gtk_box_pack_start(GTK_BOX(hbox),
1948 txt_name = gtk_entry_new(),
1952 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
1954 gtk_widget_show_all(dialog);
1956 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1958 repoman_dialog_add_repo(rmi,
1959 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
1963 gtk_widget_hide(dialog);
1965 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1970 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
1973 printf("%s()\n", __PRETTY_FUNCTION__);
1975 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
1976 _("Replace all repositories with the default repository?"));
1978 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1980 /* First, delete all existing repositories. */
1981 while(rmi->repo_edits)
1982 repoman_delete(rmi, 0);
1984 /* Now, add the default repository. */
1985 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
1987 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
1988 REPO_DEFAULT_MAP_URI);
1990 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
1992 gtk_widget_destroy(confirm);
1994 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1999 repoman_download(GtkWidget *widget, RepoManInfo *rmi)
2002 printf("%s()\n", __PRETTY_FUNCTION__);
2004 confirm = hildon_note_new_confirmation(
2005 GTK_WINDOW(rmi->dialog),
2006 _("Maemo Mapper will now download and add a list of "
2007 "possibly-duplicate repositories from the internet. "
2010 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2016 GnomeVFSResult vfs_result;
2017 printf("%s()\n", __PRETTY_FUNCTION__);
2019 /* Get repo config file from www.gnuite.com. */
2020 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2021 "http://www.gnuite.com/nokia770/maemo-mapper/repos.txt",
2024 popup_error(rmi->dialog,
2025 _("An error occurred while retrieving the repositories. "
2026 "The web service may be temporarily down."));
2027 g_printerr("Error while download repositories: %s\n",
2028 gnome_vfs_result_to_string(vfs_result));
2030 /* Parse each line as a reposotory. */
2033 for(head = bytes; head && *head; head = tail)
2035 gchar buffer[BUFFER_SIZE];
2038 tail = strchr(head, '\n');
2041 rd = settings_parse_repo(head);
2042 snprintf(buffer, sizeof(buffer), "%s.db", rd->db_filename);
2043 rei = repoman_dialog_add_repo(
2044 rmi, g_strdup(rd->name));
2045 /* Initialize fields with data from the RepoData object. */
2046 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2047 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), buffer);
2048 hildon_controlbar_set_value(
2049 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2051 hildon_controlbar_set_value(
2052 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2053 rd->view_zoom_steps);
2054 gtk_toggle_button_set_active(
2055 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2057 gtk_toggle_button_set_active(
2058 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2060 hildon_number_editor_set_value(
2061 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2063 hildon_number_editor_set_value(
2064 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2070 gtk_widget_destroy(confirm);
2072 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2079 static RepoManInfo rmi;
2080 static GtkWidget *dialog = NULL;
2081 static GtkWidget *hbox = NULL;
2082 static GtkWidget *btn_rename = NULL;
2083 static GtkWidget *btn_delete = NULL;
2084 static GtkWidget *btn_new = NULL;
2085 static GtkWidget *btn_reset = NULL;
2086 static GtkWidget *btn_download = NULL;
2087 gint i, curr_repo_index = 0;
2089 printf("%s()\n", __PRETTY_FUNCTION__);
2093 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
2094 _("Manage Repositories"),
2095 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2096 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2099 /* Enable the help button. */
2101 hildon_help_dialog_help_enable(
2103 ossohelp_dialog_help_enable(
2105 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
2108 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2109 btn_reset = gtk_button_new_with_label(_("Reset...")));
2110 g_signal_connect(G_OBJECT(btn_reset), "clicked",
2111 G_CALLBACK(repoman_reset), &rmi);
2113 /* Download button. */
2114 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2115 btn_download = gtk_button_new_with_label(_("Download...")));
2116 g_signal_connect(G_OBJECT(btn_download), "clicked",
2117 G_CALLBACK(repoman_download), &rmi);
2119 /* Cancel button. */
2120 gtk_dialog_add_button(GTK_DIALOG(dialog),
2121 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2123 hbox = gtk_hbox_new(FALSE, 4);
2125 gtk_box_pack_start(GTK_BOX(hbox),
2126 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
2128 gtk_box_pack_start(GTK_BOX(hbox),
2129 gtk_vseparator_new(), FALSE, FALSE, 4);
2130 gtk_box_pack_start(GTK_BOX(hbox),
2131 btn_rename = gtk_button_new_with_label(_("Rename...")),
2133 gtk_box_pack_start(GTK_BOX(hbox),
2134 btn_delete = gtk_button_new_with_label(_("Delete...")),
2136 gtk_box_pack_start(GTK_BOX(hbox),
2137 btn_new = gtk_button_new_with_label(_("New...")),
2140 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2141 hbox, FALSE, FALSE, 4);
2143 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2144 gtk_hseparator_new(), TRUE, TRUE, 4);
2145 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2146 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
2148 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
2149 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
2151 rmi.repo_edits = NULL;
2153 /* Connect signals. */
2154 g_signal_connect(G_OBJECT(btn_rename), "clicked",
2155 G_CALLBACK(repoman_dialog_rename), &rmi);
2156 g_signal_connect(G_OBJECT(btn_delete), "clicked",
2157 G_CALLBACK(repoman_dialog_delete), &rmi);
2158 g_signal_connect(G_OBJECT(btn_new), "clicked",
2159 G_CALLBACK(repoman_dialog_new), &rmi);
2160 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
2161 G_CALLBACK(repoman_dialog_select), &rmi);
2164 /* Populate combo box and pages in notebook. */
2165 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
2167 RepoData *rd = (RepoData*)curr->data;
2168 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
2170 /* Initialize fields with data from the RepoData object. */
2171 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
2172 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
2174 hildon_controlbar_set_value(
2175 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
2177 hildon_controlbar_set_value(
2178 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
2179 rd->view_zoom_steps);
2180 gtk_toggle_button_set_active(
2181 GTK_TOGGLE_BUTTON(rei->chk_double_size),
2183 gtk_toggle_button_set_active(
2184 GTK_TOGGLE_BUTTON(rei->chk_nextable),
2186 hildon_number_editor_set_value(
2187 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
2189 hildon_number_editor_set_value(
2190 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
2192 if(rd == _curr_repo)
2193 curr_repo_index = i;
2196 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
2197 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
2199 gtk_widget_show_all(dialog);
2201 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2203 /* Iterate through repos and verify each. */
2204 gboolean verified = TRUE;
2207 gchar *old_curr_repo_name = _curr_repo->name;
2209 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2211 /* Check the ranges for the min and max zoom levels. */
2212 RepoEditInfo *rei = curr->data;
2213 if(hildon_number_editor_get_value(
2214 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
2215 < hildon_number_editor_get_value(
2216 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
2224 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
2226 _("Minimum Downloadable Zoom must be less than "
2227 "Maximum Downloadable Zoom."));
2231 /* We're good to replace. Remove old _repo_list menu items. */
2232 menu_maps_remove_repos();
2233 /* But keep the repo list in memory, in case downloads are using it. */
2236 /* Write new _repo_list. */
2237 curr_repo_index = gtk_combo_box_get_active(
2238 GTK_COMBO_BOX(rmi.cmb_repos));
2240 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
2242 RepoEditInfo *rei = curr->data;
2243 RepoData *rd = g_new(RepoData, 1);
2244 rd->name = g_strdup(rei->name);
2245 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
2246 rd->db_filename = gnome_vfs_expand_initial_tilde(
2247 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
2248 rd->dl_zoom_steps = hildon_controlbar_get_value(
2249 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
2250 rd->view_zoom_steps = hildon_controlbar_get_value(
2251 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
2252 rd->double_size = gtk_toggle_button_get_active(
2253 GTK_TOGGLE_BUTTON(rei->chk_double_size));
2254 rd->nextable = gtk_toggle_button_get_active(
2255 GTK_TOGGLE_BUTTON(rei->chk_nextable));
2256 rd->min_zoom = hildon_number_editor_get_value(
2257 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
2258 rd->max_zoom = hildon_number_editor_get_value(
2259 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
2262 _repo_list = g_list_append(_repo_list, rd);
2264 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
2266 else if(i == curr_repo_index)
2270 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
2271 menu_maps_add_repos();
2277 gtk_widget_hide(dialog);
2279 /* Clear out the notebook entries. */
2280 while(rmi.repo_edits)
2281 repoman_delete(&rmi, 0);
2283 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
2285 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2290 mapman_by_area(gdouble start_lat, gdouble start_lon,
2291 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
2292 MapUpdateType update_type,
2293 gint download_batch_id)
2295 gint start_unitx, start_unity, end_unitx, end_unity;
2300 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
2303 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
2304 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
2306 /* Swap if they specified flipped lats or lons. */
2307 if(start_unitx > end_unitx)
2309 gint swap = start_unitx;
2310 start_unitx = end_unitx;
2313 if(start_unity > end_unity)
2315 gint swap = start_unity;
2316 start_unity = end_unity;
2320 /* First, get the number of maps to download. */
2321 for(z = 0; z <= MAX_ZOOM; ++z)
2323 if(gtk_toggle_button_get_active(
2324 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2326 gint start_tilex, start_tiley, end_tilex, end_tiley;
2327 start_tilex = unit2ztile(start_unitx, z);
2328 start_tiley = unit2ztile(start_unity, z);
2329 end_tilex = unit2ztile(end_unitx, z);
2330 end_tiley = unit2ztile(end_unity, z);
2331 num_maps += (end_tilex - start_tilex + 1)
2332 * (end_tiley - start_tiley + 1);
2336 if(update_type == MAP_UPDATE_DELETE)
2338 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
2339 num_maps, _("maps "));
2343 snprintf(buffer, sizeof(buffer),
2344 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2345 num_maps, _("maps"), _("up to about"),
2346 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2348 confirm = hildon_note_new_confirmation(
2349 GTK_WINDOW(mapman_info->dialog), buffer);
2351 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2353 gtk_widget_destroy(confirm);
2354 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2358 g_mutex_lock(_mut_priority_mutex);
2359 for(z = 0; z <= MAX_ZOOM; ++z)
2361 if(gtk_toggle_button_get_active(
2362 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2364 gint start_tilex, start_tiley, end_tilex, end_tiley;
2366 start_tilex = unit2ztile(start_unitx, z);
2367 start_tiley = unit2ztile(start_unity, z);
2368 end_tilex = unit2ztile(end_unitx, z);
2369 end_tiley = unit2ztile(end_unity, z);
2370 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
2372 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
2374 /* Make sure this tile is even possible. */
2375 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
2376 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
2378 mapdb_initiate_update(_curr_repo, z, tilex, tiley,
2379 update_type, download_batch_id,
2380 (abs(tilex - unit2tile(_next_center.unitx))
2381 + abs(tiley - unit2tile(_next_center.unity))),
2388 g_mutex_unlock(_mut_priority_mutex);
2390 gtk_widget_destroy(confirm);
2391 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2396 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
2397 gint download_batch_id)
2400 gint prev_tilex, prev_tiley, num_maps = 0, z;
2403 gint radius = hildon_number_editor_get_value(
2404 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
2405 printf("%s()\n", __PRETTY_FUNCTION__);
2407 /* First, get the number of maps to download. */
2408 for(z = 0; z <= MAX_ZOOM; ++z)
2410 if(gtk_toggle_button_get_active(
2411 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2415 for(curr = _route.head - 1; curr++ != _route.tail; )
2419 gint tilex = unit2ztile(curr->unitx, z);
2420 gint tiley = unit2ztile(curr->unity, z);
2421 if(tilex != prev_tilex || tiley != prev_tiley)
2424 num_maps += (abs((gint)tilex - prev_tilex) + 1)
2425 * (abs((gint)tiley - prev_tiley) + 1) - 1;
2433 num_maps *= 0.625 * pow(radius + 1, 1.85);
2435 if(update_type == MAP_UPDATE_DELETE)
2437 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
2438 _("Confirm DELETION of"), _("about"),
2439 num_maps, _("maps "));
2443 snprintf(buffer, sizeof(buffer),
2444 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2446 num_maps, _("maps"), _("up to about"),
2447 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2449 confirm = hildon_note_new_confirmation(
2450 GTK_WINDOW(mapman_info->dialog), buffer);
2452 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2454 gtk_widget_destroy(confirm);
2455 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2459 /* Now, do the actual download. */
2460 g_mutex_lock(_mut_priority_mutex);
2461 for(z = 0; z <= MAX_ZOOM; ++z)
2463 if(gtk_toggle_button_get_active(
2464 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2468 for(curr = _route.head - 1; curr++ != _route.tail; )
2472 gint tilex = unit2ztile(curr->unitx, z);
2473 gint tiley = unit2ztile(curr->unity, z);
2474 if(tilex != prev_tilex || tiley != prev_tiley)
2476 gint minx, miny, maxx, maxy, x, y;
2479 minx = MIN(tilex, prev_tilex) - radius;
2480 miny = MIN(tiley, prev_tiley) - radius;
2481 maxx = MAX(tilex, prev_tilex) + radius;
2482 maxy = MAX(tiley, prev_tiley) + radius;
2486 minx = tilex - radius;
2487 miny = tiley - radius;
2488 maxx = tilex + radius;
2489 maxy = tiley + radius;
2491 for(x = minx; x <= maxx; x++)
2493 for(y = miny; y <= maxy; y++)
2495 /* Make sure this tile is even possible. */
2497 < unit2ztile(WORLD_SIZE_UNITS, z)
2499 < unit2ztile(WORLD_SIZE_UNITS, z))
2501 mapdb_initiate_update(_curr_repo, z, x, y,
2502 update_type, download_batch_id,
2503 (abs(tilex - unit2tile(
2504 _next_center.unitx))
2505 + abs(tiley - unit2tile(
2506 _next_center.unity))),
2518 g_mutex_unlock(_mut_priority_mutex);
2519 _route_dl_radius = radius;
2520 gtk_widget_destroy(confirm);
2521 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2526 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
2529 printf("%s()\n", __PRETTY_FUNCTION__);
2530 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
2531 /* This is the second page (the "Zoom" page) - clear the checks. */
2532 for(z = 0; z <= MAX_ZOOM; ++z)
2533 gtk_toggle_button_set_active(
2534 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
2537 /* This is the first page (the "Area" page) - clear the text fields. */
2538 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
2539 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
2540 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
2541 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
2543 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2546 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
2548 printf("%s()\n", __PRETTY_FUNCTION__);
2549 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
2550 gtk_toggle_button_get_active(
2551 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
2553 if(gtk_toggle_button_get_active(
2554 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
2555 gtk_widget_show(mapman_info->tbl_area);
2556 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
2557 gtk_widget_hide(mapman_info->tbl_area);
2559 gtk_widget_set_sensitive(mapman_info->num_route_radius,
2560 gtk_toggle_button_get_active(
2561 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
2562 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2568 static GtkWidget *dialog = NULL;
2569 static GtkWidget *vbox = NULL;
2570 static GtkWidget *hbox = NULL;
2571 static GtkWidget *table = NULL;
2572 static GtkWidget *label = NULL;
2573 static GtkWidget *button = NULL;
2574 static GtkWidget *lbl_gps_lat = NULL;
2575 static GtkWidget *lbl_gps_lon = NULL;
2576 static GtkWidget *lbl_center_lat = NULL;
2577 static GtkWidget *lbl_center_lon = NULL;
2578 static MapmanInfo mapman_info;
2582 printf("%s()\n", __PRETTY_FUNCTION__);
2586 popup_error(_window, "To manage maps, you must set a valid repository "
2587 "database filename in the \"Manage Repositories\" dialog.");
2588 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2594 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
2596 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2597 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2600 /* Enable the help button. */
2602 hildon_help_dialog_help_enable(
2604 ossohelp_dialog_help_enable(
2606 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
2609 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2610 button = gtk_button_new_with_label(_("Clear")));
2611 g_signal_connect(G_OBJECT(button), "clicked",
2612 G_CALLBACK(mapman_clear), &mapman_info);
2614 /* Cancel button. */
2615 gtk_dialog_add_button(GTK_DIALOG(dialog),
2616 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2618 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2619 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
2622 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2623 vbox = gtk_vbox_new(FALSE, 2),
2624 label = gtk_label_new(_("Setup")));
2625 gtk_notebook_set_tab_label_packing(
2626 GTK_NOTEBOOK(mapman_info.notebook), vbox,
2627 FALSE, FALSE, GTK_PACK_START);
2629 gtk_box_pack_start(GTK_BOX(vbox),
2630 hbox = gtk_hbox_new(FALSE, 4),
2632 gtk_box_pack_start(GTK_BOX(hbox),
2633 mapman_info.rad_download = gtk_radio_button_new_with_label(
2634 NULL,_("Download Maps")),
2636 gtk_box_pack_start(GTK_BOX(hbox),
2637 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2639 gtk_container_add(GTK_CONTAINER(label),
2640 mapman_info.chk_overwrite
2641 = gtk_check_button_new_with_label(_("Overwrite"))),
2643 gtk_box_pack_start(GTK_BOX(vbox),
2644 mapman_info.rad_delete
2645 = gtk_radio_button_new_with_label_from_widget(
2646 GTK_RADIO_BUTTON(mapman_info.rad_download),
2650 gtk_box_pack_start(GTK_BOX(vbox),
2651 gtk_hseparator_new(),
2654 gtk_box_pack_start(GTK_BOX(vbox),
2655 mapman_info.rad_by_area
2656 = gtk_radio_button_new_with_label(NULL,
2657 _("By Area (see tab)")),
2659 gtk_box_pack_start(GTK_BOX(vbox),
2660 hbox = gtk_hbox_new(FALSE, 4),
2662 gtk_box_pack_start(GTK_BOX(hbox),
2663 mapman_info.rad_by_route
2664 = gtk_radio_button_new_with_label_from_widget(
2665 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
2666 _("Along Route - Radius (tiles):")),
2668 gtk_box_pack_start(GTK_BOX(hbox),
2669 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
2671 hildon_number_editor_set_value(
2672 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
2677 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2678 table = gtk_table_new(5, 5, FALSE),
2679 label = gtk_label_new(_("Zoom")));
2680 gtk_notebook_set_tab_label_packing(
2681 GTK_NOTEBOOK(mapman_info.notebook), table,
2682 FALSE, FALSE, GTK_PACK_START);
2683 gtk_table_attach(GTK_TABLE(table),
2684 label = gtk_label_new(
2685 _("Zoom Levels to Download: (0 = most detail)")),
2686 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
2687 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2688 snprintf(buffer, sizeof(buffer), "%d", 0);
2689 gtk_table_attach(GTK_TABLE(table),
2690 mapman_info.chk_zoom_levels[0]
2691 = gtk_check_button_new_with_label(buffer),
2692 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
2693 for(z = 0; z < MAX_ZOOM; ++z)
2695 snprintf(buffer, sizeof(buffer), "%d", z + 1);
2696 gtk_table_attach(GTK_TABLE(table),
2697 mapman_info.chk_zoom_levels[z + 1]
2698 = gtk_check_button_new_with_label(buffer),
2699 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
2704 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2705 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
2706 label = gtk_label_new(_("Area")));
2708 /* Label Columns. */
2709 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2710 label = gtk_label_new(_("Latitude")),
2711 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
2712 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2713 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2714 label = gtk_label_new(_("Longitude")),
2715 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
2716 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2719 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2720 label = gtk_label_new(_("GPS Location")),
2721 0, 1, 1, 2, GTK_FILL, 0, 4, 0);
2722 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2723 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2724 lbl_gps_lat = gtk_label_new(""),
2725 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
2726 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
2727 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
2728 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2729 lbl_gps_lon = gtk_label_new(""),
2730 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
2731 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
2732 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
2735 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2736 label = gtk_label_new(_("View Center")),
2737 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
2738 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2739 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2740 lbl_center_lat = gtk_label_new(""),
2741 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
2742 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
2743 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
2744 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2745 lbl_center_lon = gtk_label_new(""),
2746 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
2747 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
2748 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
2750 /* default values for Top Left and Bottom Right are defined by the
2751 * rectangle of the current and the previous Center */
2754 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2755 label = gtk_label_new(_("Top-Left")),
2756 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
2757 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2758 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2759 mapman_info.txt_topleft_lat = gtk_entry_new(),
2760 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
2761 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
2762 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
2763 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2765 "hildon-input-mode",
2766 HILDON_GTK_INPUT_MODE_FULL, NULL);
2768 HILDON_INPUT_MODE_HINT,
2769 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2770 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2774 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2775 mapman_info.txt_topleft_lon = gtk_entry_new(),
2776 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
2777 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
2778 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
2779 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2781 "hildon-input-mode",
2782 HILDON_GTK_INPUT_MODE_FULL, NULL);
2784 HILDON_INPUT_MODE_HINT,
2785 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2786 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2792 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2793 label = gtk_label_new(_("Bottom-Right")),
2794 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
2795 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2796 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2797 mapman_info.txt_botright_lat = gtk_entry_new(),
2798 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
2799 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2800 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
2801 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2803 "hildon-input-mode",
2804 HILDON_GTK_INPUT_MODE_FULL, NULL);
2806 HILDON_INPUT_MODE_HINT,
2807 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2808 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2812 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2813 mapman_info.txt_botright_lon = gtk_entry_new(),
2814 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
2815 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2816 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
2817 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2819 "hildon-input-mode",
2820 HILDON_GTK_INPUT_MODE_FULL, NULL);
2822 HILDON_INPUT_MODE_HINT,
2823 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2824 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2829 /* Default action is to download by area. */
2830 gtk_toggle_button_set_active(
2831 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
2833 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
2834 G_CALLBACK(mapman_update_state), &mapman_info);
2835 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
2836 G_CALLBACK(mapman_update_state), &mapman_info);
2837 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
2838 G_CALLBACK(mapman_update_state), &mapman_info);
2839 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
2840 G_CALLBACK(mapman_update_state), &mapman_info);
2843 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
2844 * output (and parsed) as locale-dependent. */
2846 gtk_widget_set_sensitive(mapman_info.rad_by_route,
2847 _route.head != _route.tail);
2849 lat_format(_gps.lat, buffer);
2850 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
2851 lon_format(_gps.lon, buffer);
2852 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
2854 unit2latlon(_center.unitx, _center.unity, lat, lon);
2855 lat_format(lat, buffer);
2856 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
2857 lon_format(lon, buffer);
2858 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
2860 /* Initialize to the bounds of the screen. */
2862 _center.unitx - pixel2unit(MAX(_view_width_pixels,
2863 _view_height_pixels) / 2),
2864 _center.unity - pixel2unit(MAX(_view_width_pixels,
2865 _view_height_pixels) / 2), lat, lon);
2866 BOUND(lat, -90.f, 90.f);
2867 BOUND(lon, -180.f, 180.f);
2868 lat_format(lat, buffer);
2869 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
2870 lon_format(lon, buffer);
2871 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
2874 _center.unitx + pixel2unit(MAX(_view_width_pixels,
2875 _view_height_pixels) / 2),
2876 _center.unity + pixel2unit(MAX(_view_width_pixels,
2877 _view_height_pixels) / 2), lat, lon);
2878 BOUND(lat, -90.f, 90.f);
2879 BOUND(lon, -180.f, 180.f);
2880 lat_format(lat, buffer);
2881 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
2882 lon_format(lon, buffer);
2883 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
2885 /* Initialize zoom levels. */
2888 for(i = 0; i <= MAX_ZOOM; i++)
2890 gtk_toggle_button_set_active(
2891 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
2894 gtk_toggle_button_set_active(
2895 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
2896 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
2898 gtk_widget_show_all(dialog);
2900 mapman_update_state(NULL, &mapman_info);
2902 if(_curr_repo->type != REPOTYPE_NONE)
2904 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
2908 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
2910 _("NOTE: You must set a Map URI in the current repository in "
2911 "order to download maps."));
2914 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2916 MapUpdateType update_type;
2917 static gint8 download_batch_id = INT8_MIN;
2919 if(gtk_toggle_button_get_active(
2920 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
2921 update_type = MAP_UPDATE_DELETE;
2922 else if(gtk_toggle_button_get_active(
2923 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
2924 update_type = MAP_UPDATE_OVERWRITE;
2926 update_type = MAP_UPDATE_ADD;
2928 ++download_batch_id;
2929 if(gtk_toggle_button_get_active(
2930 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
2932 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
2939 gdouble start_lat, start_lon, end_lat, end_lon;
2941 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
2942 start_lat = strdmstod(text, &error_check);
2943 if(text == error_check || start_lat < -90. || start_lat > 90.) {
2944 popup_error(dialog, _("Invalid Top-Left Latitude"));
2948 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
2949 start_lon = strdmstod(text, &error_check);
2950 if(text == error_check || start_lon < -180. || start_lon>180.) {
2951 popup_error(dialog, _("Invalid Top-Left Longitude"));
2955 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
2956 end_lat = strdmstod(text, &error_check);
2957 if(text == error_check || end_lat < -90. || end_lat > 90.) {
2958 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
2962 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
2963 end_lon = strdmstod(text, &error_check);
2964 if(text == error_check || end_lon < -180. || end_lon > 180.) {
2965 popup_error(dialog,_("Invalid Bottom-Right Longitude"));
2969 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
2970 &mapman_info, update_type, download_batch_id))
2975 gtk_widget_hide(dialog);
2977 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);