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];
114 mapdb_exists(RepoData *repo, gint zoom, gint tilex, gint tiley)
117 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
118 repo->name, zoom, tilex, tiley);
120 g_mutex_lock(_mapdb_mutex);
124 /* There is no cache. Return FALSE. */
125 g_mutex_unlock(_mapdb_mutex);
126 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
131 /* Attempt to retrieve map from database. */
132 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 1, zoom)
133 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 2, tilex)
134 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_exists, 3, tiley)
135 && SQLITE_ROW == sqlite3_step(repo->stmt_map_exists)
136 && sqlite3_column_int(repo->stmt_map_exists, 0) > 0)
144 sqlite3_reset(repo->stmt_map_exists);
153 d.dptr = (gchar*)&key;
154 d.dsize = sizeof(key);
155 exists = gdbm_exists(repo->db, d);
159 g_mutex_unlock(_mapdb_mutex);
161 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, exists);
166 mapdb_get(RepoData *repo, gint zoom, gint tilex, gint tiley)
168 GdkPixbuf *pixbuf = NULL;
169 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
170 repo->name, zoom, tilex, tiley);
172 g_mutex_lock(_mapdb_mutex);
176 /* There is no cache. Return NULL. */
177 g_mutex_unlock(_mapdb_mutex);
178 vprintf("%s(): return NULL\n", __PRETTY_FUNCTION__);
183 /* Attempt to retrieve map from database. */
184 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
185 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
186 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
187 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select))
189 const gchar *bytes = NULL;
190 gint size = sqlite3_column_bytes(repo->stmt_map_select, 0);
192 /* "Pixbufs" of size less than or equal to MAX_PIXBUF_DUP_SIZE are
193 * actually keys into the dups table. */
194 if(size <= MAX_PIXBUF_DUP_SIZE)
196 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
197 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_select, 1, hash)
198 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_select))
200 bytes = sqlite3_column_blob(repo->stmt_dup_select, 0);
201 size = sqlite3_column_bytes(repo->stmt_dup_select, 0);
205 /* Not there? Delete the entry, then. */
206 if(SQLITE_OK != sqlite3_bind_int(
207 repo->stmt_map_delete, 1, zoom)
208 || SQLITE_OK != sqlite3_bind_int(
209 repo->stmt_map_delete, 2, tilex)
210 || SQLITE_OK != sqlite3_bind_int(
211 repo->stmt_map_delete, 3, tiley)
212 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
214 printf("Error in stmt_map_delete: %s\n",
215 sqlite3_errmsg(repo->db));
217 sqlite3_reset(repo->stmt_map_delete);
219 /* We have no bytes to return to the caller. */
222 /* Don't reset the statement yet - we need the blob. */
226 bytes = sqlite3_column_blob(repo->stmt_map_select, 0);
230 GError *error = NULL;
231 GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
232 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
233 gdk_pixbuf_loader_close(loader, &error);
235 pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
236 g_object_unref(loader);
238 if(size <= MAX_PIXBUF_DUP_SIZE)
239 sqlite3_reset(repo->stmt_dup_select);
241 sqlite3_reset(repo->stmt_map_select);
250 d.dptr = (gchar*)&key;
251 d.dsize = sizeof(key);
252 d = gdbm_fetch(repo->db, d);
255 GError *error = NULL;
256 GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
257 gdk_pixbuf_loader_write(loader, d.dptr, d.dsize, NULL);
259 gdk_pixbuf_loader_close(loader, &error);
261 pixbuf = g_object_ref(gdk_pixbuf_loader_get_pixbuf(loader));
262 g_object_unref(loader);
267 g_mutex_unlock(_mapdb_mutex);
269 vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, pixbuf);
275 mapdb_checkdec(RepoData *repo, gint zoom, gint tilex, gint tiley)
277 gboolean success = TRUE;
278 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
279 repo->name, zoom, tilex, tiley);
281 /* First, we have to check if the old map was a dup. */
282 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 1, zoom)
283 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 2, tilex)
284 && SQLITE_OK == sqlite3_bind_int(repo->stmt_map_select, 3, tiley)
285 && SQLITE_ROW == sqlite3_step(repo->stmt_map_select)
286 && sqlite3_column_bytes(repo->stmt_map_select, 0)
287 <= MAX_PIXBUF_DUP_SIZE)
289 /* Old map was indeed a dup. Decrement the reference count. */
290 gint hash = sqlite3_column_int(repo->stmt_map_select, 0);
291 if(SQLITE_OK != sqlite3_bind_int(
292 repo->stmt_dup_decrem, 1, hash)
293 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_decrem)
294 || SQLITE_OK != sqlite3_bind_int(
295 repo->stmt_dup_delete, 1, hash)
296 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_delete))
299 printf("Error in stmt_dup_decrem: %s\n",
300 sqlite3_errmsg(repo->db));
302 sqlite3_reset(repo->stmt_dup_delete);
303 sqlite3_reset(repo->stmt_dup_decrem);
305 sqlite3_reset(repo->stmt_map_select);
307 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
313 mapdb_update(gboolean exists, RepoData *repo,
314 gint zoom, gint tilex, gint tiley, void *bytes, gint size)
321 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
322 repo->name, zoom, tilex, tiley);
324 g_mutex_lock(_mapdb_mutex);
328 /* There is no cache. Return FALSE. */
329 g_mutex_unlock(_mapdb_mutex);
330 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
335 /* At least try to open a transaction. */
336 sqlite3_step(repo->stmt_trans_begin);
337 sqlite3_reset(repo->stmt_trans_begin);
339 /* Pixbufs of size MAX_PIXBUF_DUP_SIZE or less are special. They are
340 * probably PNGs of a single color (like blue for water or beige for empty
341 * land). To reduce redundancy in the database, we will store them in a
342 * separate table and, in the maps table, only refer to them. */
343 if(size <= MAX_PIXBUF_DUP_SIZE)
345 /* Duplicate pixbuf. */
348 /* First, check if we need to remove a count from the dups table.*/
349 mapdb_checkdec(repo, zoom, tilex, tiley);
353 /* Compute hash of the bytes. */
354 gchar *cur = bytes, *end = bytes + size;
357 hash = (hash << 5) - hash + *(++cur);
359 /* Check if dup already exists. */
360 if(SQLITE_OK == sqlite3_bind_int(repo->stmt_dup_exists, 1, hash)
361 && SQLITE_ROW == sqlite3_step(repo->stmt_dup_exists)
362 && sqlite3_column_int(repo->stmt_dup_exists, 0) > 0)
364 /* Dup already exists - increment existing entry. */
365 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_increm,1, hash)
366 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_increm))
369 printf("Error in stmt_dup_increm: %s\n",
370 sqlite3_errmsg(repo->db));
372 sqlite3_reset(repo->stmt_dup_increm);
376 /* Dup doesn't exist - add new entry. */
377 if(SQLITE_OK != sqlite3_bind_int(repo->stmt_dup_insert,1, hash)
378 || SQLITE_OK != sqlite3_bind_blob(repo->stmt_dup_insert,
379 2, bytes, size, NULL)
380 || SQLITE_DONE != sqlite3_step(repo->stmt_dup_insert))
383 printf("Error in stmt_dup_insert: %s\n",
384 sqlite3_errmsg(repo->db));
386 sqlite3_reset(repo->stmt_dup_insert);
388 sqlite3_reset(repo->stmt_dup_exists);
390 /* Now, if successful so far, we fall through the end of this if
391 * statement and insert the hash as the blob. Setting bytes to NULL
392 * is the signal to do this. */
398 stmt = exists ? repo->stmt_map_update : repo->stmt_map_insert;
400 /* Attempt to insert map from database. */
401 if(SQLITE_OK != (bytes ? sqlite3_bind_blob(stmt, 1, bytes, size, NULL)
402 : sqlite3_bind_int(stmt, 1, hash))
403 || SQLITE_OK != sqlite3_bind_int(stmt, 2, zoom)
404 || SQLITE_OK != sqlite3_bind_int(stmt, 3, tilex)
405 || SQLITE_OK != sqlite3_bind_int(stmt, 4, tiley)
406 || SQLITE_DONE != sqlite3_step(stmt))
409 printf("Error in mapdb_update: %s\n", sqlite3_errmsg(repo->db));
416 sqlite3_step(repo->stmt_trans_commit);
417 sqlite3_reset(repo->stmt_trans_commit);
421 sqlite3_step(repo->stmt_trans_rollback);
422 sqlite3_reset(repo->stmt_trans_rollback);
433 dkey.dptr = (gchar*)&key;
434 dkey.dsize = sizeof(key);
437 success = !gdbm_store(repo->db, dkey, dcon, GDBM_REPLACE);
440 g_mutex_unlock(_mapdb_mutex);
442 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
447 mapdb_delete(RepoData *repo, gint zoom, gint tilex, gint tiley)
449 gint success = FALSE;
450 vprintf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
451 repo->name, zoom, tilex, tiley);
453 g_mutex_lock(_mapdb_mutex);
457 /* There is no cache. Return FALSE. */
458 g_mutex_unlock(_mapdb_mutex);
459 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
464 /* At least try to open a transaction. */
465 sqlite3_step(repo->stmt_trans_begin);
466 sqlite3_reset(repo->stmt_trans_begin);
468 /* First, check if we need to remove a count from the dups table. */
469 /* Then, attempt to delete map from database. */
470 if(!mapdb_checkdec(repo, zoom, tilex, tiley)
471 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 1, zoom)
472 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 2, tilex)
473 || SQLITE_OK != sqlite3_bind_int(repo->stmt_map_delete, 3, tiley)
474 || SQLITE_DONE != sqlite3_step(repo->stmt_map_delete))
477 printf("Error in stmt_map_delete: %s\n",
478 sqlite3_errmsg(repo->db));
480 sqlite3_reset(repo->stmt_map_delete);
484 sqlite3_step(repo->stmt_trans_commit);
485 sqlite3_reset(repo->stmt_trans_commit);
489 sqlite3_step(repo->stmt_trans_rollback);
490 sqlite3_reset(repo->stmt_trans_rollback);
500 d.dptr = (gchar*)&key;
501 d.dsize = sizeof(key);
502 success = !gdbm_delete(repo->db, d);
505 g_mutex_unlock(_mapdb_mutex);
507 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, success);
512 set_repo_type(RepoData *repo)
514 printf("%s(%s)\n", __PRETTY_FUNCTION__, repo->url);
516 if(repo->url && *repo->url)
518 gchar *url = g_utf8_strdown(repo->url, -1);
520 /* Determine type of repository. */
521 if(strstr(url, "service=wms"))
522 repo->type = REPOTYPE_WMS;
523 else if(strstr(url, "%s"))
524 repo->type = REPOTYPE_QUAD_QRST;
525 else if(strstr(url, "%0d"))
526 repo->type = REPOTYPE_XYZ_INV;
527 else if(strstr(url, "%0s"))
528 repo->type = REPOTYPE_QUAD_ZERO;
530 repo->type = REPOTYPE_XYZ;
535 repo->type = REPOTYPE_NONE;
537 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
540 /* Returns the directory containing the given database filename, or NULL
541 * if the database file could not be created. */
543 repo_make_db(RepoData *rd)
545 printf("%s(%s)\n", __PRETTY_FUNCTION__, rd->db_filename);
549 db_dirname = g_path_get_dirname(rd->db_filename);
551 /* Check if db_filename is a directory and ask to upgrade. */
552 if(g_file_test(rd->db_filename, G_FILE_TEST_IS_DIR))
554 gchar buffer[BUFFER_SIZE];
555 gchar *new_name = g_strdup_printf("%s.db", rd->db_filename);
556 g_free(rd->db_filename);
557 rd->db_filename = new_name;
559 snprintf(buffer, sizeof(buffer), "%s",
560 _("The current repository is in a legacy format and will "
561 "be converted. You should delete your old maps if you "
562 "no longer plan to use them."));
563 popup_error(_window, buffer);
566 if(g_mkdir_with_parents(db_dirname, 0755))
573 if(!g_file_test(rd->db_filename, G_FILE_TEST_EXISTS))
575 fd = g_creat(rd->db_filename, 0644);
584 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__,
585 g_file_test(rd->db_filename, G_FILE_TEST_EXISTS));
586 return g_file_test(rd->db_filename, G_FILE_TEST_EXISTS);
590 repo_set_curr(RepoData *rd)
592 printf("%s()\n", __PRETTY_FUNCTION__);
593 if(!rd->db_filename || !*rd->db_filename
600 g_mutex_lock(_mapdb_mutex);
602 sqlite3_close(_curr_repo->db);
604 gdbm_close(_curr_repo->db);
606 _curr_repo->db = NULL;
607 g_mutex_unlock(_mapdb_mutex);
611 /* Set the current repository! */
614 /* Set up the database. */
615 if(_curr_repo->db_filename && *_curr_repo->db_filename)
619 if(SQLITE_OK != (sqlite3_open(_curr_repo->db_filename,
621 /* Open worked. Now create tables, failing if they already exist.*/
622 || (sqlite3_exec(_curr_repo->db,
623 "create table maps ("
628 "primary key (zoom, tilex, tiley))"
630 "create table dups ("
631 "hash integer primary key, "
634 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
635 /* Prepare select map statement. */
636 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
637 "select pixbuf from maps "
638 "where zoom = ? and tilex = ? and tiley = ?",
639 -1, &_curr_repo->stmt_map_select, NULL)
640 /* Prepare exists map statement. */
641 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
642 "select count(*) from maps "
643 "where zoom = ? and tilex = ? and tiley = ?",
644 -1, &_curr_repo->stmt_map_exists, NULL)
645 /* Prepare insert map statement. */
646 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
647 "insert into maps (pixbuf, zoom, tilex, tiley)"
648 " values (?, ?, ?, ?)",
649 -1, &_curr_repo->stmt_map_insert, NULL)
650 /* Prepare update map statement. */
651 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
652 "update maps set pixbuf = ? "
653 "where zoom = ? and tilex = ? and tiley = ?",
654 -1, &_curr_repo->stmt_map_update, NULL)
655 /* Prepare delete map statement. */
656 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
658 "where zoom = ? and tilex = ? and tiley = ?",
659 -1, &_curr_repo->stmt_map_delete, NULL)
661 /* Prepare select-by-map dup statement. */
662 /* Prepare select-by-hash dup statement. */
663 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
664 "select pixbuf from dups "
666 -1, &_curr_repo->stmt_dup_select, NULL)
667 /* Prepare exists map statement. */
668 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
669 "select count(*) from dups "
671 -1, &_curr_repo->stmt_dup_exists, NULL)
672 /* Prepare insert dup statement. */
673 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
674 "insert into dups (hash, pixbuf, uses) "
676 -1, &_curr_repo->stmt_dup_insert, NULL)
677 /* Prepare increment dup statement. */
678 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
680 "set uses = uses + 1 "
682 -1, &_curr_repo->stmt_dup_increm, NULL)
683 /* Prepare decrement dup statement. */
684 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
686 "set uses = uses - 1 "
688 -1, &_curr_repo->stmt_dup_decrem, NULL)
689 /* Prepare delete dup statement. */
690 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
692 "where hash = ? and uses <= 0",
693 -1, &_curr_repo->stmt_dup_delete, NULL)
695 /* Prepare begin-transaction statement. */
696 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
698 -1, &_curr_repo->stmt_trans_begin, NULL)
699 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
700 "commit transaction",
701 -1, &_curr_repo->stmt_trans_commit, NULL)
702 || SQLITE_OK != sqlite3_prepare(_curr_repo->db,
703 "rollback transaction", -1,
704 &_curr_repo->stmt_trans_rollback, NULL))
706 gchar buffer[BUFFER_SIZE];
707 snprintf(buffer, sizeof(buffer), "%s: %s\n%s",
708 _("Failed to open map database for repository"),
709 sqlite3_errmsg(_curr_repo->db),
710 _("Downloaded maps will not be cached."));
711 sqlite3_close(_curr_repo->db);
712 _curr_repo->db = NULL;
713 popup_error(_window, buffer);
716 _curr_repo->db = gdbm_open(_curr_repo->db_filename,
717 0, GDBM_WRCREAT, 0644, NULL);
720 gchar buffer[BUFFER_SIZE];
721 snprintf(buffer, sizeof(buffer), "%s\n%s",
722 _("Failed to open map database for repository"),
723 _("Downloaded maps will not be cached."));
724 _curr_repo->db = NULL;
725 popup_error(_window, buffer);
731 _curr_repo->db = NULL;
733 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
738 gchar buffer[BUFFER_SIZE];
739 snprintf(buffer, sizeof(buffer), "%s: %s",
740 _("Unable to create map database for repository"), rd->name);
741 popup_error(_window, buffer);
743 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
749 * Given a wms uri pattern, compute the coordinate transformation and
751 * 'proj' is used for the conversion
754 map_convert_wms_to_wms(gint tilex, gint tiley, gint zoomlevel, gchar* uri)
757 gchar cmd[BUFFER_SIZE], srs[BUFFER_SIZE];
760 gdouble lon1, lat1, lon2, lat2;
762 gchar *widthstr = strcasestr(uri,"WIDTH=");
763 gchar *heightstr = strcasestr(uri,"HEIGHT=");
764 gchar *srsstr = strcasestr(uri,"SRS=EPSG");
765 gchar *srsstre = strchr(srsstr,'&');
766 vprintf("%s()\n", __PRETTY_FUNCTION__);
768 /* missing: test if found */
770 strncpy(srs+4,srsstr+8,256);
771 /* missing: test srsstre-srsstr < 526 */
772 srs[srsstre-srsstr-4] = 0;
773 /* convert to lower, as WMC is EPSG and cs2cs is epsg */
775 gint dwidth = widthstr ? atoi(widthstr+6) - TILE_SIZE_PIXELS : 0;
776 gint dheight = heightstr ? atoi(heightstr+7) - TILE_SIZE_PIXELS : 0;
778 unit2latlon(tile2zunit(tilex,zoomlevel)
779 - pixel2zunit(dwidth/2,zoomlevel),
780 tile2zunit(tiley+1,zoomlevel)
781 + pixel2zunit((dheight+1)/2,zoomlevel),
784 unit2latlon(tile2zunit(tilex+1,zoomlevel)
785 + pixel2zunit((dwidth+1)/2,zoomlevel),
786 tile2zunit(tiley,zoomlevel)
787 - pixel2zunit(dheight/2,zoomlevel),
790 setlocale(LC_NUMERIC, "C");
792 snprintf(cmd, sizeof(cmd),
793 "(echo \"%.6f %.6f\"; echo \"%.6f %.6f\") | "
794 "/usr/bin/cs2cs +proj=longlat +datum=WGS84 +to +init=%s -f %%.6f "
796 lon1, lat1, lon2, lat2, srs);
797 vprintf("Running command: %s\n", cmd);
798 system_retcode = system(cmd);
801 g_printerr("cs2cs returned error code %d\n",
802 WEXITSTATUS(system_retcode));
803 else if(!(in = g_fopen("/tmp/tmpcs2cs","r")))
804 g_printerr("Cannot open results of conversion\n");
805 else if(5 != fscanf(in,"%lf %lf %s %lf %lf",
806 &lon1, &lat1, cmd, &lon2, &lat2))
808 g_printerr("Wrong conversion\n");
814 ret = g_strdup_printf(uri, lon1, lat1, lon2, lat2);
817 setlocale(LC_NUMERIC, "");
819 vprintf("%s(): return %s\n", __PRETTY_FUNCTION__, ret);
825 * Given the xyz coordinates of our map coordinate system, write the qrst
826 * quadtree coordinates to buffer.
829 map_convert_coords_to_quadtree_string(gint x, gint y, gint zoomlevel,
830 gchar *buffer, const gchar initial,
831 const gchar *const quadrant)
835 vprintf("%s()\n", __PRETTY_FUNCTION__);
840 for(n = MAX_ZOOM - zoomlevel; n >= 0; n--)
842 gint xbit = (x >> n) & 1;
843 gint ybit = (y >> n) & 1;
844 *ptr++ = quadrant[xbit + 2 * ybit];
847 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
851 * Construct the URL that we should fetch, based on the current URI format.
852 * This method works differently depending on if a "%s" string is present in
853 * the URI format, since that would indicate a quadtree-based map coordinate
857 map_construct_url(RepoData *repo, gint zoom, gint tilex, gint tiley)
860 vprintf("%s()\n", __PRETTY_FUNCTION__);
864 retval = g_strdup_printf(repo->url,
865 tilex, tiley, zoom - (MAX_ZOOM - 16));
868 case REPOTYPE_XYZ_INV:
869 retval = g_strdup_printf(repo->url,
870 MAX_ZOOM + 1 - zoom, tilex, tiley);
873 case REPOTYPE_QUAD_QRST:
875 gchar location[MAX_ZOOM + 2];
876 map_convert_coords_to_quadtree_string(
877 tilex, tiley, zoom, location, 't', "qrts");
878 retval = g_strdup_printf(repo->url, location);
882 case REPOTYPE_QUAD_ZERO:
884 /* This is a zero-based quadtree URI. */
885 gchar location[MAX_ZOOM + 2];
886 map_convert_coords_to_quadtree_string(
887 tilex, tiley, zoom, location, '\0', "0123");
888 retval = g_strdup_printf(repo->url, location);
893 retval = map_convert_wms_to_wms(tilex, tiley, zoom, repo->url);
897 retval = g_strdup(repo->url);
900 vprintf("%s(): return \"%s\"\n", __PRETTY_FUNCTION__, retval);
905 mapdb_initiate_update_banner_idle()
907 if(!_download_banner && _num_downloads != _curr_download)
909 _download_banner = hildon_banner_show_progress(
910 _window, NULL, _("Processing Maps"));
911 /* If we're not connected, then hide the banner immediately. It will
912 * be unhidden if/when we're connected. */
913 if(!_conic_is_connected)
914 gtk_widget_hide(_download_banner);
920 * Initiate a download of the given xyz coordinates using the given buffer
921 * as the URL. If the map already exists on disk, or if we are already
922 * downloading the map, then this method does nothing.
925 mapdb_initiate_update(RepoData *repo, gint zoom, gint tilex, gint tiley,
926 gint update_type, gint batch_id, gint priority,
927 ThreadLatch *refresh_latch)
930 MapUpdateTask *old_mut;
931 gboolean is_replacing = FALSE;
932 vprintf("%s(%s, %d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
933 repo->name, zoom, tilex, tiley, update_type);
935 mut = g_slice_new(MapUpdateTask);
938 /* Could not allocate memory. */
939 g_printerr("Out of memory in allocation of update task #%d\n",
946 mut->update_type = update_type;
948 /* Lock the mutex if this is an auto-update. */
949 if(update_type == MAP_UPDATE_AUTO)
950 g_mutex_lock(_mut_priority_mutex);
951 if(NULL != (old_mut = g_hash_table_lookup(_mut_exists_table, mut)))
953 /* Check if new mut is in a newer batch that the old mut.
954 * We use vfs_result to indicate a MUT that is already in the process
955 * of being downloaded. */
956 if(old_mut->batch_id < batch_id && old_mut->vfs_result < 0)
958 /* It is, so remove the old one so we can re-add this one. */
959 g_hash_table_remove(_mut_exists_table, old_mut);
960 g_tree_remove(_mut_priority_tree, old_mut);
961 g_slice_free(MapUpdateTask, old_mut);
966 /* It's not, so just ignore it. */
967 if(update_type == MAP_UPDATE_AUTO)
968 g_mutex_unlock(_mut_priority_mutex);
969 g_slice_free(MapUpdateTask, mut);
970 vprintf("%s(): return FALSE (1)\n", __PRETTY_FUNCTION__);
975 g_hash_table_insert(_mut_exists_table, mut, mut);
978 mut->refresh_latch = refresh_latch;
979 mut->priority = priority;
980 mut->batch_id = batch_id;
982 mut->vfs_result = -1;
984 g_tree_insert(_mut_priority_tree, mut, mut);
986 /* Unlock the mutex if this is an auto-update. */
987 if(update_type == MAP_UPDATE_AUTO)
988 g_mutex_unlock(_mut_priority_mutex);
992 /* Increment download count and (possibly) display banner. */
993 if(++_num_downloads == 20 && !_download_banner)
994 g_idle_add((GSourceFunc)mapdb_initiate_update_banner_idle, NULL);
996 /* This doesn't need to be thread-safe. Extras in the pool don't
997 * really make a difference. */
998 if(g_thread_pool_get_num_threads(_mut_thread_pool)
999 < g_thread_pool_get_max_threads(_mut_thread_pool))
1000 g_thread_pool_push(_mut_thread_pool, (gpointer)1, NULL);
1003 vprintf("%s(): return FALSE (2)\n", __PRETTY_FUNCTION__);
1008 get_next_mut(gpointer key, gpointer value, MapUpdateTask **data)
1017 printf("%s()\n", __PRETTY_FUNCTION__);
1019 /* Make sure things are inititalized. */
1025 gboolean refresh_sent = FALSE;
1026 MapUpdateTask *mut = NULL;
1028 /* Wait until we are connected. */
1029 conic_ensure_connected();
1031 /* Get the next MUT from the mut tree. */
1032 g_mutex_lock(_mut_priority_mutex);
1033 g_tree_foreach(_mut_priority_tree, (GTraverseFunc)get_next_mut, &mut);
1036 /* No more MUTs to process. Return. */
1037 g_mutex_unlock(_mut_priority_mutex);
1040 /* Mark this MUT as "in-progress". */
1041 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1042 g_tree_remove(_mut_priority_tree, mut);
1043 g_mutex_unlock(_mut_priority_mutex);
1045 printf("%s(%s, %d, %d, %d)\n", __PRETTY_FUNCTION__,
1046 mut->repo->name, mut->zoom, mut->tilex, mut->tiley);
1048 if(mut->repo != _curr_repo)
1050 /* Do nothing, except report that there is no error. */
1051 mut->vfs_result = GNOME_VFS_OK;
1053 else if(mut->update_type == MAP_UPDATE_DELETE)
1055 /* Easy - just delete the entry from the database. We don't care
1056 * about failures (sorry). */
1058 mapdb_delete(mut->repo, mut->zoom, mut->tilex, mut->tiley);
1060 /* Report that there is no error. */
1061 mut->vfs_result = GNOME_VFS_OK;
1063 else for(retries = INITIAL_DOWNLOAD_RETRIES; retries > 0; --retries)
1065 gboolean exists = FALSE;
1069 GdkPixbufLoader *loader;
1071 gint zoom, tilex, tiley;
1072 GError *error = NULL;
1075 /* First check for existence. */
1076 exists = mut->repo->db
1077 ? mapdb_exists(mut->repo, mut->zoom,
1078 mut->tilex, mut->tiley)
1080 if(exists && mut->update_type == MAP_UPDATE_ADD)
1082 /* Map already exists, and we're not going to overwrite. */
1083 /* Report that there is no error. */
1084 mut->vfs_result = GNOME_VFS_OK;
1088 /* First check for existence. */
1089 if(mut->update_type == MAP_UPDATE_ADD)
1091 /* We don't want to overwrite, so check for existence. */
1092 /* Map already exists, and we're not going to overwrite. */
1093 if(mapdb_exists(mut->repo, mut->zoom,
1094 mut->tilex,mut->tiley))
1096 /* Report that there is no error. */
1097 mut->vfs_result = GNOME_VFS_OK;
1103 /* First, construct the URL from which we will get the data. */
1104 src_url = map_construct_url(mut->repo, mut->zoom,
1105 mut->tilex, mut->tiley);
1107 /* Now, attempt to read the entire contents of the URL. */
1108 mut->vfs_result = gnome_vfs_read_entire_file(
1109 src_url, &size, &bytes);
1111 if(mut->vfs_result != GNOME_VFS_OK || !bytes)
1114 printf("Error reading URL: %s\n",
1115 gnome_vfs_result_to_string(mut->vfs_result));
1119 /* usleep(100000); DEBUG */
1121 /* Attempt to parse the bytes into a pixbuf. */
1122 loader = gdk_pixbuf_loader_new();
1123 gdk_pixbuf_loader_write(loader, bytes, size, NULL);
1124 gdk_pixbuf_loader_close(loader, &error);
1125 if(error || (NULL == (mut->pixbuf = g_object_ref(
1126 gdk_pixbuf_loader_get_pixbuf(loader)))))
1128 mut->vfs_result = GNOME_VFS_NUM_ERRORS;
1130 g_object_unref(mut->pixbuf);
1133 g_object_unref(loader);
1134 printf("Error parsing pixbuf: %s\n",
1135 error ? error->message : "?");
1138 g_object_unref(loader);
1140 /* Copy database-relevant mut data before we release it. */
1146 /* Pass the mut to the GTK thread for redrawing, but only if a
1147 * redraw isn't already in the pipeline. */
1148 if(mut->refresh_latch)
1150 /* Wait until the latch is open. */
1151 g_mutex_lock(mut->refresh_latch->mutex);
1152 while(!mut->refresh_latch->is_open)
1154 g_cond_wait(mut->refresh_latch->cond,
1155 mut->refresh_latch->mutex);
1157 /* Latch is open. Decrement the number of waiters and
1158 * check if we're the last waiter to run. */
1159 if(mut->refresh_latch->is_done_adding_tasks)
1161 if(++mut->refresh_latch->num_done
1162 == mut->refresh_latch->num_tasks)
1164 /* Last waiter. Free the latch resources. */
1165 g_mutex_unlock(mut->refresh_latch->mutex);
1166 g_cond_free(mut->refresh_latch->cond);
1167 g_mutex_free(mut->refresh_latch->mutex);
1168 g_slice_free(ThreadLatch, mut->refresh_latch);
1169 mut->refresh_latch = NULL;
1173 /* Not the last waiter. Signal the next waiter.*/
1174 g_cond_signal(mut->refresh_latch->cond);
1175 g_mutex_unlock(mut->refresh_latch->mutex);
1179 g_mutex_unlock(mut->refresh_latch->mutex);
1182 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1183 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1184 refresh_sent = TRUE;
1186 /* DO NOT USE mut FROM THIS POINT ON. */
1188 /* Also attempt to add to the database. */
1189 mapdb_update(exists, repo, zoom,
1190 tilex, tiley, bytes, size);
1198 g_idle_add_full(G_PRIORITY_HIGH_IDLE,
1199 (GSourceFunc)map_download_refresh_idle, mut, NULL);
1202 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1207 mut_exists_hashfunc(const MapUpdateTask *a)
1209 gint sum = a->zoom + a->tilex + a->tiley + a->update_type;
1210 return g_int_hash(&sum);
1214 mut_exists_equalfunc(const MapUpdateTask *a, const MapUpdateTask *b)
1216 return (a->tilex == b->tilex
1217 && a->tiley == b->tiley
1218 && a->zoom == b->zoom
1219 && a->update_type == b->update_type);
1223 mut_priority_comparefunc(const MapUpdateTask *a, const MapUpdateTask *b)
1225 /* The update_type enum is sorted in order of ascending priority. */
1226 gint diff = (b->update_type - a->update_type);
1229 diff = (b->batch_id - a->batch_id); /* More recent ones first. */
1232 diff = (a->priority - b->priority); /* Lower priority numbers first. */
1236 /* At this point, we don't care, so just pick arbitrarily. */
1237 diff = (a->tilex - b->tilex);
1240 diff = (a->tiley - b->tiley);
1243 return (a->zoom - b->zoom);
1247 repoman_dialog_select(GtkWidget *widget, RepoManInfo *rmi)
1249 printf("%s()\n", __PRETTY_FUNCTION__);
1250 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1251 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
1252 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1257 repoman_dialog_browse(GtkWidget *widget, BrowseInfo *browse_info)
1261 printf("%s()\n", __PRETTY_FUNCTION__);
1263 dialog = GTK_WIDGET(
1264 hildon_file_chooser_dialog_new(GTK_WINDOW(browse_info->dialog),
1265 GTK_FILE_CHOOSER_ACTION_SAVE));
1267 gtk_file_chooser_set_uri(GTK_FILE_CHOOSER(dialog),
1268 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1270 /* Work around a bug in HildonFileChooserDialog. */
1271 basename = g_path_get_basename(
1272 gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
1273 g_object_set(G_OBJECT(dialog), "autonaming", FALSE, NULL);
1274 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), basename);
1276 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog)))
1278 gchar *filename = gtk_file_chooser_get_filename(
1279 GTK_FILE_CHOOSER(dialog));
1280 gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
1284 gtk_widget_destroy(dialog);
1286 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1291 repoman_dialog_rename(GtkWidget *widget, RepoManInfo *rmi)
1293 static GtkWidget *hbox = NULL;
1294 static GtkWidget *label = NULL;
1295 static GtkWidget *txt_name = NULL;
1296 static GtkWidget *dialog = NULL;
1297 printf("%s()\n", __PRETTY_FUNCTION__);
1301 dialog = gtk_dialog_new_with_buttons(_("New Name"),
1302 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1303 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1304 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1307 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1308 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1310 gtk_box_pack_start(GTK_BOX(hbox),
1311 label = gtk_label_new(_("Name")),
1313 gtk_box_pack_start(GTK_BOX(hbox),
1314 txt_name = gtk_entry_new(),
1319 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1320 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1321 gtk_entry_set_text(GTK_ENTRY(txt_name), rei->name);
1324 gtk_widget_show_all(dialog);
1326 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1328 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1329 RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
1331 rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
1332 gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos),
1333 active, g_strdup(rei->name));
1334 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
1335 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
1339 gtk_widget_hide(dialog);
1341 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1346 repoman_delete(RepoManInfo *rmi, gint index)
1348 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), index);
1349 gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), index);
1350 rmi->repo_edits = g_list_remove_link(
1352 g_list_nth(rmi->repo_edits, index));
1356 repoman_dialog_delete(GtkWidget *widget, RepoManInfo *rmi, gint index)
1360 printf("%s()\n", __PRETTY_FUNCTION__);
1362 if(gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1363 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1366 popup_error(rmi->dialog,
1367 _("Cannot delete the last repository - there must be at"
1368 " lease one repository."));
1369 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1373 snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
1374 _("Confirm delete of repository"),
1375 gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
1377 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),buffer);
1379 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1381 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
1382 repoman_delete(rmi, active);
1383 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1387 gtk_widget_destroy(confirm);
1392 static RepoEditInfo*
1393 repoman_dialog_add_repo(RepoManInfo *rmi, gchar *name)
1399 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
1400 printf("%s(%s)\n", __PRETTY_FUNCTION__, name);
1405 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook),
1406 vbox = gtk_vbox_new(FALSE, 4),
1407 gtk_label_new(name));
1409 /* Prevent destruction of notebook page, because the destruction causes
1410 * a seg fault (!?!?) */
1411 gtk_object_ref(GTK_OBJECT(vbox));
1413 gtk_box_pack_start(GTK_BOX(vbox),
1414 table = gtk_table_new(2, 2, FALSE),
1416 /* Map download URI. */
1417 gtk_table_attach(GTK_TABLE(table),
1418 label = gtk_label_new(_("URL Format")),
1419 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1420 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1421 gtk_table_attach(GTK_TABLE(table),
1422 rei->txt_url = gtk_entry_new(),
1423 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1425 /* Map Directory. */
1426 gtk_table_attach(GTK_TABLE(table),
1427 label = gtk_label_new(_("Cache DB")),
1428 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1429 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1430 gtk_table_attach(GTK_TABLE(table),
1431 hbox = gtk_hbox_new(FALSE, 4),
1432 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1433 gtk_box_pack_start(GTK_BOX(hbox),
1434 rei->txt_db_filename = gtk_entry_new(),
1436 gtk_box_pack_start(GTK_BOX(hbox),
1437 rei->btn_browse = gtk_button_new_with_label(_("Browse...")),
1440 /* Initialize cache dir */
1442 gchar buffer[BUFFER_SIZE];
1443 snprintf(buffer, sizeof(buffer), "%s.db", name);
1444 gchar *db_base = gnome_vfs_expand_initial_tilde(
1445 REPO_DEFAULT_CACHE_BASE);
1446 gchar *db_filename = gnome_vfs_uri_make_full_from_relative(
1448 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), db_filename);
1449 g_free(db_filename);
1453 gtk_box_pack_start(GTK_BOX(vbox),
1454 table = gtk_table_new(3, 2, FALSE),
1457 /* Download Zoom Steps. */
1458 gtk_table_attach(GTK_TABLE(table),
1459 label = gtk_label_new(_("Download Zoom Steps")),
1460 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1461 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1462 gtk_table_attach(GTK_TABLE(table),
1463 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1464 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1465 gtk_container_add(GTK_CONTAINER(label),
1466 rei->num_dl_zoom_steps = hildon_controlbar_new());
1467 hildon_controlbar_set_range(
1468 HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
1469 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1470 REPO_DEFAULT_DL_ZOOM_STEPS);
1471 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
1473 /* Download Zoom Steps. */
1474 gtk_table_attach(GTK_TABLE(table),
1475 label = gtk_label_new(_("View Zoom Steps")),
1476 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1477 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1478 gtk_table_attach(GTK_TABLE(table),
1479 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1480 1, 2, 1, 2, GTK_FILL, 0, 2, 0);
1481 gtk_container_add(GTK_CONTAINER(label),
1482 rei->num_view_zoom_steps = hildon_controlbar_new());
1483 hildon_controlbar_set_range(
1484 HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
1485 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1486 REPO_DEFAULT_VIEW_ZOOM_STEPS);
1487 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
1489 gtk_table_attach(GTK_TABLE(table),
1490 label = gtk_vseparator_new(),
1491 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 0);
1494 gtk_table_attach(GTK_TABLE(table),
1495 rei->chk_double_size = gtk_check_button_new_with_label(
1496 _("Double Pixels")),
1497 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
1498 gtk_toggle_button_set_active(
1499 GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
1502 gtk_table_attach(GTK_TABLE(table),
1503 rei->chk_nextable = gtk_check_button_new_with_label(
1505 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
1506 gtk_toggle_button_set_active(
1507 GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
1509 /* Downloadable Zoom Levels. */
1510 gtk_table_attach(GTK_TABLE(table),
1511 label = gtk_label_new(_("Downloadable Zooms:")),
1512 0, 1, 2, 3, GTK_FILL, 0, 2, 0);
1513 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1514 gtk_table_attach(GTK_TABLE(table),
1515 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
1516 1, 4, 2, 3, GTK_FILL, 0, 2, 0);
1517 gtk_container_add(GTK_CONTAINER(label),
1518 hbox = gtk_hbox_new(FALSE, 4));
1519 gtk_box_pack_start(GTK_BOX(hbox),
1520 label = gtk_label_new(_("Min.")),
1522 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1523 gtk_box_pack_start(GTK_BOX(hbox),
1524 rei->num_min_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
1526 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_min_zoom), 4);
1527 gtk_box_pack_start(GTK_BOX(hbox),
1528 label = gtk_label_new(""),
1530 gtk_box_pack_start(GTK_BOX(hbox),
1531 label = gtk_label_new(_("Max.")),
1533 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1534 gtk_box_pack_start(GTK_BOX(hbox),
1535 rei->num_max_zoom = hildon_number_editor_new(MIN_ZOOM, MAX_ZOOM),
1537 hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(rei->num_max_zoom),20);
1539 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
1541 /* Connect signals. */
1542 rei->browse_info.dialog = rmi->dialog;
1543 rei->browse_info.txt = rei->txt_db_filename;
1544 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked",
1545 G_CALLBACK(repoman_dialog_browse),
1548 gtk_widget_show_all(vbox);
1550 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
1551 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
1552 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(
1553 gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))),
1556 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1561 repoman_dialog_new(GtkWidget *widget, RepoManInfo *rmi)
1563 static GtkWidget *hbox = NULL;
1564 static GtkWidget *label = NULL;
1565 static GtkWidget *txt_name = NULL;
1566 static GtkWidget *dialog = NULL;
1567 printf("%s()\n", __PRETTY_FUNCTION__);
1571 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
1572 GTK_WINDOW(rmi->dialog), GTK_DIALOG_MODAL,
1573 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1574 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1577 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1578 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1580 gtk_box_pack_start(GTK_BOX(hbox),
1581 label = gtk_label_new(_("Name")),
1583 gtk_box_pack_start(GTK_BOX(hbox),
1584 txt_name = gtk_entry_new(),
1588 gtk_entry_set_text(GTK_ENTRY(txt_name), "");
1590 gtk_widget_show_all(dialog);
1592 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1594 repoman_dialog_add_repo(rmi,
1595 g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
1599 gtk_widget_hide(dialog);
1601 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1606 repoman_reset(GtkWidget *widget, RepoManInfo *rmi)
1609 printf("%s()\n", __PRETTY_FUNCTION__);
1611 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
1612 _("Replace all repositories with the default repository?"));
1614 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1616 /* First, delete all existing repositories. */
1617 while(rmi->repo_edits)
1618 repoman_delete(rmi, 0);
1620 /* Now, add the default repository. */
1621 repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
1623 GTK_ENTRY(((RepoEditInfo*)rmi->repo_edits->data)->txt_url),
1624 REPO_DEFAULT_MAP_URI);
1626 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
1628 gtk_widget_destroy(confirm);
1630 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1635 repoman_download(GtkWidget *widget, RepoManInfo *rmi)
1638 printf("%s()\n", __PRETTY_FUNCTION__);
1640 confirm = hildon_note_new_confirmation(
1641 GTK_WINDOW(rmi->dialog),
1642 _("Maemo Mapper will now download and add a list of "
1643 "possibly-duplicate repositories from the internet. "
1646 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1652 GnomeVFSResult vfs_result;
1653 printf("%s()\n", __PRETTY_FUNCTION__);
1655 /* Get repo config file from www.gnuite.com. */
1656 if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
1657 "http://www.gnuite.com/nokia770/maemo-mapper/repos.txt",
1660 popup_error(rmi->dialog,
1661 _("An error occurred while retrieving the repositories. "
1662 "The web service may be temporarily down."));
1663 g_printerr("Error while download repositories: %s\n",
1664 gnome_vfs_result_to_string(vfs_result));
1666 /* Parse each line as a reposotory. */
1669 for(head = bytes; head && *head; head = tail)
1671 gchar buffer[BUFFER_SIZE];
1674 tail = strchr(head, '\n');
1677 rd = settings_parse_repo(head);
1678 snprintf(buffer, sizeof(buffer), "%s.db", rd->db_filename);
1679 rei = repoman_dialog_add_repo(
1680 rmi, g_strdup(rd->name));
1681 /* Initialize fields with data from the RepoData object. */
1682 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
1683 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename), buffer);
1684 hildon_controlbar_set_value(
1685 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1687 hildon_controlbar_set_value(
1688 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1689 rd->view_zoom_steps);
1690 gtk_toggle_button_set_active(
1691 GTK_TOGGLE_BUTTON(rei->chk_double_size),
1693 gtk_toggle_button_set_active(
1694 GTK_TOGGLE_BUTTON(rei->chk_nextable),
1696 hildon_number_editor_set_value(
1697 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
1699 hildon_number_editor_set_value(
1700 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
1706 gtk_widget_destroy(confirm);
1708 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1715 static RepoManInfo rmi;
1716 static GtkWidget *dialog = NULL;
1717 static GtkWidget *hbox = NULL;
1718 static GtkWidget *btn_rename = NULL;
1719 static GtkWidget *btn_delete = NULL;
1720 static GtkWidget *btn_new = NULL;
1721 static GtkWidget *btn_reset = NULL;
1722 static GtkWidget *btn_download = NULL;
1723 gint i, curr_repo_index = 0;
1725 printf("%s()\n", __PRETTY_FUNCTION__);
1729 rmi.dialog = dialog = gtk_dialog_new_with_buttons(
1730 _("Manage Repositories"),
1731 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
1732 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1735 /* Enable the help button. */
1737 hildon_help_dialog_help_enable(
1739 ossohelp_dialog_help_enable(
1741 GTK_DIALOG(dialog), HELP_ID_REPOMAN, _osso);
1744 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1745 btn_reset = gtk_button_new_with_label(_("Reset...")));
1746 g_signal_connect(G_OBJECT(btn_reset), "clicked",
1747 G_CALLBACK(repoman_reset), &rmi);
1749 /* Download button. */
1750 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1751 btn_download = gtk_button_new_with_label(_("Download...")));
1752 g_signal_connect(G_OBJECT(btn_download), "clicked",
1753 G_CALLBACK(repoman_download), &rmi);
1755 /* Cancel button. */
1756 gtk_dialog_add_button(GTK_DIALOG(dialog),
1757 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
1759 hbox = gtk_hbox_new(FALSE, 4);
1761 gtk_box_pack_start(GTK_BOX(hbox),
1762 rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
1764 gtk_box_pack_start(GTK_BOX(hbox),
1765 gtk_vseparator_new(), FALSE, FALSE, 4);
1766 gtk_box_pack_start(GTK_BOX(hbox),
1767 btn_rename = gtk_button_new_with_label(_("Rename...")),
1769 gtk_box_pack_start(GTK_BOX(hbox),
1770 btn_delete = gtk_button_new_with_label(_("Delete...")),
1772 gtk_box_pack_start(GTK_BOX(hbox),
1773 btn_new = gtk_button_new_with_label(_("New...")),
1776 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1777 hbox, FALSE, FALSE, 4);
1779 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1780 gtk_hseparator_new(), TRUE, TRUE, 4);
1781 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1782 rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
1784 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
1785 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
1787 rmi.repo_edits = NULL;
1789 /* Connect signals. */
1790 g_signal_connect(G_OBJECT(btn_rename), "clicked",
1791 G_CALLBACK(repoman_dialog_rename), &rmi);
1792 g_signal_connect(G_OBJECT(btn_delete), "clicked",
1793 G_CALLBACK(repoman_dialog_delete), &rmi);
1794 g_signal_connect(G_OBJECT(btn_new), "clicked",
1795 G_CALLBACK(repoman_dialog_new), &rmi);
1796 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed",
1797 G_CALLBACK(repoman_dialog_select), &rmi);
1800 /* Populate combo box and pages in notebook. */
1801 for(i = 0, curr = _repo_list; curr; curr = curr->next, i++)
1803 RepoData *rd = (RepoData*)curr->data;
1804 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
1806 /* Initialize fields with data from the RepoData object. */
1807 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
1808 gtk_entry_set_text(GTK_ENTRY(rei->txt_db_filename),
1810 hildon_controlbar_set_value(
1811 HILDON_CONTROLBAR(rei->num_dl_zoom_steps),
1813 hildon_controlbar_set_value(
1814 HILDON_CONTROLBAR(rei->num_view_zoom_steps),
1815 rd->view_zoom_steps);
1816 gtk_toggle_button_set_active(
1817 GTK_TOGGLE_BUTTON(rei->chk_double_size),
1819 gtk_toggle_button_set_active(
1820 GTK_TOGGLE_BUTTON(rei->chk_nextable),
1822 hildon_number_editor_set_value(
1823 HILDON_NUMBER_EDITOR(rei->num_min_zoom),
1825 hildon_number_editor_set_value(
1826 HILDON_NUMBER_EDITOR(rei->num_max_zoom),
1828 if(rd == _curr_repo)
1829 curr_repo_index = i;
1832 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
1833 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
1835 gtk_widget_show_all(dialog);
1837 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1839 /* Iterate through repos and verify each. */
1840 gboolean verified = TRUE;
1843 gchar *old_curr_repo_name = _curr_repo->name;
1845 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
1847 /* Check the ranges for the min and max zoom levels. */
1848 RepoEditInfo *rei = curr->data;
1849 if(hildon_number_editor_get_value(
1850 HILDON_NUMBER_EDITOR(rei->num_max_zoom))
1851 < hildon_number_editor_get_value(
1852 HILDON_NUMBER_EDITOR(rei->num_min_zoom)))
1860 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i);
1862 _("Minimum Downloadable Zoom must be less than "
1863 "Maximum Downloadable Zoom."));
1867 /* We're good to replace. Remove old _repo_list menu items. */
1868 menu_maps_remove_repos();
1869 /* But keep the repo list in memory, in case downloads are using it. */
1872 /* Write new _repo_list. */
1873 curr_repo_index = gtk_combo_box_get_active(
1874 GTK_COMBO_BOX(rmi.cmb_repos));
1876 for(i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++)
1878 RepoEditInfo *rei = curr->data;
1879 RepoData *rd = g_new(RepoData, 1);
1880 rd->name = g_strdup(rei->name);
1881 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
1882 rd->db_filename = gnome_vfs_expand_initial_tilde(
1883 gtk_entry_get_text(GTK_ENTRY(rei->txt_db_filename)));
1884 rd->dl_zoom_steps = hildon_controlbar_get_value(
1885 HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
1886 rd->view_zoom_steps = hildon_controlbar_get_value(
1887 HILDON_CONTROLBAR(rei->num_view_zoom_steps));
1888 rd->double_size = gtk_toggle_button_get_active(
1889 GTK_TOGGLE_BUTTON(rei->chk_double_size));
1890 rd->nextable = gtk_toggle_button_get_active(
1891 GTK_TOGGLE_BUTTON(rei->chk_nextable));
1892 rd->min_zoom = hildon_number_editor_get_value(
1893 HILDON_NUMBER_EDITOR(rei->num_min_zoom));
1894 rd->max_zoom = hildon_number_editor_get_value(
1895 HILDON_NUMBER_EDITOR(rei->num_max_zoom));
1898 _repo_list = g_list_append(_repo_list, rd);
1900 if(!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
1902 else if(i == curr_repo_index)
1906 repo_set_curr((RepoData*)g_list_first(_repo_list)->data);
1907 menu_maps_add_repos();
1913 gtk_widget_hide(dialog);
1915 /* Clear out the notebook entries. */
1916 while(rmi.repo_edits)
1917 repoman_delete(&rmi, 0);
1919 map_set_zoom(_zoom); /* make sure we're at an appropriate zoom level. */
1921 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1926 mapman_by_area(gdouble start_lat, gdouble start_lon,
1927 gdouble end_lat, gdouble end_lon, MapmanInfo *mapman_info,
1928 MapUpdateType update_type,
1929 gint download_batch_id)
1931 gint start_unitx, start_unity, end_unitx, end_unity;
1936 printf("%s(%f, %f, %f, %f)\n", __PRETTY_FUNCTION__, start_lat, start_lon,
1939 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
1940 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
1942 /* Swap if they specified flipped lats or lons. */
1943 if(start_unitx > end_unitx)
1945 gint swap = start_unitx;
1946 start_unitx = end_unitx;
1949 if(start_unity > end_unity)
1951 gint swap = start_unity;
1952 start_unity = end_unity;
1956 /* First, get the number of maps to download. */
1957 for(z = 0; z <= MAX_ZOOM; ++z)
1959 if(gtk_toggle_button_get_active(
1960 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
1962 gint start_tilex, start_tiley, end_tilex, end_tiley;
1963 start_tilex = unit2ztile(start_unitx, z);
1964 start_tiley = unit2ztile(start_unity, z);
1965 end_tilex = unit2ztile(end_unitx, z);
1966 end_tiley = unit2ztile(end_unity, z);
1967 num_maps += (end_tilex - start_tilex + 1)
1968 * (end_tiley - start_tiley + 1);
1972 if(update_type == MAP_UPDATE_DELETE)
1974 snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"),
1975 num_maps, _("maps "));
1979 snprintf(buffer, sizeof(buffer),
1980 "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
1981 num_maps, _("maps"), _("up to about"),
1982 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
1984 confirm = hildon_note_new_confirmation(
1985 GTK_WINDOW(mapman_info->dialog), buffer);
1987 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
1989 gtk_widget_destroy(confirm);
1990 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
1994 g_mutex_lock(_mut_priority_mutex);
1995 for(z = 0; z <= MAX_ZOOM; ++z)
1997 if(gtk_toggle_button_get_active(
1998 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2000 gint start_tilex, start_tiley, end_tilex, end_tiley;
2002 start_tilex = unit2ztile(start_unitx, z);
2003 start_tiley = unit2ztile(start_unity, z);
2004 end_tilex = unit2ztile(end_unitx, z);
2005 end_tiley = unit2ztile(end_unity, z);
2006 for(tiley = start_tiley; tiley <= end_tiley; tiley++)
2008 for(tilex = start_tilex; tilex <= end_tilex; tilex++)
2010 /* Make sure this tile is even possible. */
2011 if((unsigned)tilex < unit2ztile(WORLD_SIZE_UNITS, z)
2012 && (unsigned)tiley < unit2ztile(WORLD_SIZE_UNITS, z))
2014 mapdb_initiate_update(_curr_repo, z, tilex, tiley,
2015 update_type, download_batch_id,
2016 (abs(tilex - unit2tile(_next_center.unitx))
2017 + abs(tiley - unit2tile(_next_center.unity))),
2024 g_mutex_unlock(_mut_priority_mutex);
2026 gtk_widget_destroy(confirm);
2027 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2032 mapman_by_route(MapmanInfo *mapman_info, MapUpdateType update_type,
2033 gint download_batch_id)
2036 gint prev_tilex, prev_tiley, num_maps = 0, z;
2039 gint radius = hildon_number_editor_get_value(
2040 HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
2041 printf("%s()\n", __PRETTY_FUNCTION__);
2043 /* First, get the number of maps to download. */
2044 for(z = 0; z <= MAX_ZOOM; ++z)
2046 if(gtk_toggle_button_get_active(
2047 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2051 for(curr = _route.head - 1; curr++ != _route.tail; )
2055 gint tilex = unit2ztile(curr->unitx, z);
2056 gint tiley = unit2ztile(curr->unity, z);
2057 if(tilex != prev_tilex || tiley != prev_tiley)
2060 num_maps += (abs((gint)tilex - prev_tilex) + 1)
2061 * (abs((gint)tiley - prev_tiley) + 1) - 1;
2069 num_maps *= 0.625 * pow(radius + 1, 1.85);
2071 if(update_type == MAP_UPDATE_DELETE)
2073 snprintf(buffer, sizeof(buffer), "%s %s %d %s",
2074 _("Confirm DELETION of"), _("about"),
2075 num_maps, _("maps "));
2079 snprintf(buffer, sizeof(buffer),
2080 "%s %s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
2082 num_maps, _("maps"), _("up to about"),
2083 num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
2085 confirm = hildon_note_new_confirmation(
2086 GTK_WINDOW(mapman_info->dialog), buffer);
2088 if(GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm)))
2090 gtk_widget_destroy(confirm);
2091 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
2095 /* Now, do the actual download. */
2096 g_mutex_lock(_mut_priority_mutex);
2097 for(z = 0; z <= MAX_ZOOM; ++z)
2099 if(gtk_toggle_button_get_active(
2100 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z])))
2104 for(curr = _route.head - 1; curr++ != _route.tail; )
2108 gint tilex = unit2ztile(curr->unitx, z);
2109 gint tiley = unit2ztile(curr->unity, z);
2110 if(tilex != prev_tilex || tiley != prev_tiley)
2112 gint minx, miny, maxx, maxy, x, y;
2115 minx = MIN(tilex, prev_tilex) - radius;
2116 miny = MIN(tiley, prev_tiley) - radius;
2117 maxx = MAX(tilex, prev_tilex) + radius;
2118 maxy = MAX(tiley, prev_tiley) + radius;
2122 minx = tilex - radius;
2123 miny = tiley - radius;
2124 maxx = tilex + radius;
2125 maxy = tiley + radius;
2127 for(x = minx; x <= maxx; x++)
2129 for(y = miny; y <= maxy; y++)
2131 /* Make sure this tile is even possible. */
2133 < unit2ztile(WORLD_SIZE_UNITS, z)
2135 < unit2ztile(WORLD_SIZE_UNITS, z))
2137 mapdb_initiate_update(_curr_repo, z, x, y,
2138 update_type, download_batch_id,
2139 (abs(tilex - unit2tile(
2140 _next_center.unitx))
2141 + abs(tiley - unit2tile(
2142 _next_center.unity))),
2154 g_mutex_unlock(_mut_priority_mutex);
2155 _route_dl_radius = radius;
2156 gtk_widget_destroy(confirm);
2157 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2162 mapman_clear(GtkWidget *widget, MapmanInfo *mapman_info)
2165 printf("%s()\n", __PRETTY_FUNCTION__);
2166 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook)))
2167 /* This is the second page (the "Zoom" page) - clear the checks. */
2168 for(z = 0; z <= MAX_ZOOM; ++z)
2169 gtk_toggle_button_set_active(
2170 GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[z]), FALSE);
2173 /* This is the first page (the "Area" page) - clear the text fields. */
2174 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
2175 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
2176 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
2177 gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
2179 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2182 void mapman_update_state(GtkWidget *widget, MapmanInfo *mapman_info)
2184 printf("%s()\n", __PRETTY_FUNCTION__);
2185 gtk_widget_set_sensitive( mapman_info->chk_overwrite,
2186 gtk_toggle_button_get_active(
2187 GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
2189 if(gtk_toggle_button_get_active(
2190 GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
2191 gtk_widget_show(mapman_info->tbl_area);
2192 else if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook)) == 3)
2193 gtk_widget_hide(mapman_info->tbl_area);
2195 gtk_widget_set_sensitive(mapman_info->num_route_radius,
2196 gtk_toggle_button_get_active(
2197 GTK_TOGGLE_BUTTON(mapman_info->rad_by_route)));
2198 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
2204 static GtkWidget *dialog = NULL;
2205 static GtkWidget *vbox = NULL;
2206 static GtkWidget *hbox = NULL;
2207 static GtkWidget *table = NULL;
2208 static GtkWidget *label = NULL;
2209 static GtkWidget *button = NULL;
2210 static GtkWidget *lbl_gps_lat = NULL;
2211 static GtkWidget *lbl_gps_lon = NULL;
2212 static GtkWidget *lbl_center_lat = NULL;
2213 static GtkWidget *lbl_center_lon = NULL;
2214 static MapmanInfo mapman_info;
2218 printf("%s()\n", __PRETTY_FUNCTION__);
2222 popup_error(_window, "To manage maps, you must set a valid repository "
2223 "database filename in the \"Manage Repositories\" dialog.");
2224 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2230 mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(
2232 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2233 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2236 /* Enable the help button. */
2238 hildon_help_dialog_help_enable(
2240 ossohelp_dialog_help_enable(
2242 GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN, _osso);
2245 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
2246 button = gtk_button_new_with_label(_("Clear")));
2247 g_signal_connect(G_OBJECT(button), "clicked",
2248 G_CALLBACK(mapman_clear), &mapman_info);
2250 /* Cancel button. */
2251 gtk_dialog_add_button(GTK_DIALOG(dialog),
2252 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
2254 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2255 mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
2258 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2259 vbox = gtk_vbox_new(FALSE, 2),
2260 label = gtk_label_new(_("Setup")));
2261 gtk_notebook_set_tab_label_packing(
2262 GTK_NOTEBOOK(mapman_info.notebook), vbox,
2263 FALSE, FALSE, GTK_PACK_START);
2265 gtk_box_pack_start(GTK_BOX(vbox),
2266 hbox = gtk_hbox_new(FALSE, 4),
2268 gtk_box_pack_start(GTK_BOX(hbox),
2269 mapman_info.rad_download = gtk_radio_button_new_with_label(
2270 NULL,_("Download Maps")),
2272 gtk_box_pack_start(GTK_BOX(hbox),
2273 label = gtk_alignment_new(0.f, 0.5f, 0.f, 0.f),
2275 gtk_container_add(GTK_CONTAINER(label),
2276 mapman_info.chk_overwrite
2277 = gtk_check_button_new_with_label(_("Overwrite"))),
2279 gtk_box_pack_start(GTK_BOX(vbox),
2280 mapman_info.rad_delete
2281 = gtk_radio_button_new_with_label_from_widget(
2282 GTK_RADIO_BUTTON(mapman_info.rad_download),
2286 gtk_box_pack_start(GTK_BOX(vbox),
2287 gtk_hseparator_new(),
2290 gtk_box_pack_start(GTK_BOX(vbox),
2291 mapman_info.rad_by_area
2292 = gtk_radio_button_new_with_label(NULL,
2293 _("By Area (see tab)")),
2295 gtk_box_pack_start(GTK_BOX(vbox),
2296 hbox = gtk_hbox_new(FALSE, 4),
2298 gtk_box_pack_start(GTK_BOX(hbox),
2299 mapman_info.rad_by_route
2300 = gtk_radio_button_new_with_label_from_widget(
2301 GTK_RADIO_BUTTON(mapman_info.rad_by_area),
2302 _("Along Route - Radius (tiles):")),
2304 gtk_box_pack_start(GTK_BOX(hbox),
2305 mapman_info.num_route_radius = hildon_number_editor_new(0,100),
2307 hildon_number_editor_set_value(
2308 HILDON_NUMBER_EDITOR(mapman_info.num_route_radius),
2313 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2314 table = gtk_table_new(5, 5, FALSE),
2315 label = gtk_label_new(_("Zoom")));
2316 gtk_notebook_set_tab_label_packing(
2317 GTK_NOTEBOOK(mapman_info.notebook), table,
2318 FALSE, FALSE, GTK_PACK_START);
2319 gtk_table_attach(GTK_TABLE(table),
2320 label = gtk_label_new(
2321 _("Zoom Levels to Download: (0 = most detail)")),
2322 0, 4, 0, 1, GTK_FILL, 0, 4, 0);
2323 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2324 snprintf(buffer, sizeof(buffer), "%d", 0);
2325 gtk_table_attach(GTK_TABLE(table),
2326 mapman_info.chk_zoom_levels[0]
2327 = gtk_check_button_new_with_label(buffer),
2328 4, 5 , 0, 1, GTK_FILL, 0, 0, 0);
2329 for(z = 0; z < MAX_ZOOM; ++z)
2331 snprintf(buffer, sizeof(buffer), "%d", z + 1);
2332 gtk_table_attach(GTK_TABLE(table),
2333 mapman_info.chk_zoom_levels[z + 1]
2334 = gtk_check_button_new_with_label(buffer),
2335 z / 4, z / 4 + 1, z % 4 + 1, z % 4 + 2,
2340 gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
2341 mapman_info.tbl_area = gtk_table_new(5, 3, FALSE),
2342 label = gtk_label_new(_("Area")));
2344 /* Label Columns. */
2345 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2346 label = gtk_label_new(_("Latitude")),
2347 1, 2, 0, 1, GTK_FILL, 0, 4, 0);
2348 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2349 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2350 label = gtk_label_new(_("Longitude")),
2351 2, 3, 0, 1, GTK_FILL, 0, 4, 0);
2352 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2355 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2356 label = gtk_label_new(_("GPS Location")),
2357 0, 1, 1, 2, GTK_FILL, 0, 4, 0);
2358 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2359 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2360 lbl_gps_lat = gtk_label_new(""),
2361 1, 2, 1, 2, GTK_FILL, 0, 4, 0);
2362 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
2363 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
2364 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2365 lbl_gps_lon = gtk_label_new(""),
2366 2, 3, 1, 2, GTK_FILL, 0, 4, 0);
2367 gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
2368 gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
2371 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2372 label = gtk_label_new(_("View Center")),
2373 0, 1, 2, 3, GTK_FILL, 0, 4, 0);
2374 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2375 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2376 lbl_center_lat = gtk_label_new(""),
2377 1, 2, 2, 3, GTK_FILL, 0, 4, 0);
2378 gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
2379 gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
2380 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2381 lbl_center_lon = gtk_label_new(""),
2382 2, 3, 2, 3, GTK_FILL, 0, 4, 0);
2383 gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
2384 gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
2386 /* default values for Top Left and Bottom Right are defined by the
2387 * rectangle of the current and the previous Center */
2390 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2391 label = gtk_label_new(_("Top-Left")),
2392 0, 1, 3, 4, GTK_FILL, 0, 4, 0);
2393 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2394 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2395 mapman_info.txt_topleft_lat = gtk_entry_new(),
2396 1, 2, 3, 4, GTK_FILL, 0, 4, 0);
2397 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lat), 12);
2398 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
2399 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2401 "hildon-input-mode",
2402 HILDON_GTK_INPUT_MODE_FULL, NULL);
2404 HILDON_INPUT_MODE_HINT,
2405 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2406 g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
2410 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2411 mapman_info.txt_topleft_lon = gtk_entry_new(),
2412 2, 3, 3, 4, GTK_FILL, 0, 4, 0);
2413 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_topleft_lon), 12);
2414 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
2415 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2417 "hildon-input-mode",
2418 HILDON_GTK_INPUT_MODE_FULL, NULL);
2420 HILDON_INPUT_MODE_HINT,
2421 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2422 g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
2428 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2429 label = gtk_label_new(_("Bottom-Right")),
2430 0, 1, 4, 5, GTK_FILL, 0, 4, 0);
2431 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2432 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2433 mapman_info.txt_botright_lat = gtk_entry_new(),
2434 1, 2, 4, 5, GTK_FILL, 0, 4, 0);
2435 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2436 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
2437 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2439 "hildon-input-mode",
2440 HILDON_GTK_INPUT_MODE_FULL, NULL);
2442 HILDON_INPUT_MODE_HINT,
2443 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2444 g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
2448 gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
2449 mapman_info.txt_botright_lon = gtk_entry_new(),
2450 2, 3, 4, 5, GTK_FILL, 0, 4, 0);
2451 gtk_entry_set_width_chars(GTK_ENTRY(mapman_info.txt_botright_lat), 12);
2452 gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
2453 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2455 "hildon-input-mode",
2456 HILDON_GTK_INPUT_MODE_FULL, NULL);
2458 HILDON_INPUT_MODE_HINT,
2459 HILDON_INPUT_MODE_HINT_ALPHANUMERICSPECIAL, NULL);
2460 g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
2465 /* Default action is to download by area. */
2466 gtk_toggle_button_set_active(
2467 GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
2469 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked",
2470 G_CALLBACK(mapman_update_state), &mapman_info);
2471 g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked",
2472 G_CALLBACK(mapman_update_state), &mapman_info);
2473 g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked",
2474 G_CALLBACK(mapman_update_state), &mapman_info);
2475 g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked",
2476 G_CALLBACK(mapman_update_state), &mapman_info);
2479 /* Initialize fields. Do no use g_ascii_formatd; these strings will be
2480 * output (and parsed) as locale-dependent. */
2482 gtk_widget_set_sensitive(mapman_info.rad_by_route,
2483 _route.head != _route.tail);
2485 lat_format(_gps.lat, buffer);
2486 gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
2487 lon_format(_gps.lon, buffer);
2488 gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
2490 unit2latlon(_center.unitx, _center.unity, lat, lon);
2491 lat_format(lat, buffer);
2492 gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
2493 lon_format(lon, buffer);
2494 gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
2496 /* Initialize to the bounds of the screen. */
2498 _center.unitx - pixel2unit(MAX(_view_width_pixels,
2499 _view_height_pixels) / 2),
2500 _center.unity - pixel2unit(MAX(_view_width_pixels,
2501 _view_height_pixels) / 2), lat, lon);
2502 BOUND(lat, -90.f, 90.f);
2503 BOUND(lon, -180.f, 180.f);
2504 lat_format(lat, buffer);
2505 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
2506 lon_format(lon, buffer);
2507 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
2510 _center.unitx + pixel2unit(MAX(_view_width_pixels,
2511 _view_height_pixels) / 2),
2512 _center.unity + pixel2unit(MAX(_view_width_pixels,
2513 _view_height_pixels) / 2), lat, lon);
2514 BOUND(lat, -90.f, 90.f);
2515 BOUND(lon, -180.f, 180.f);
2516 lat_format(lat, buffer);
2517 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
2518 lon_format(lon, buffer);
2519 gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
2521 /* Initialize zoom levels. */
2524 for(i = 0; i <= MAX_ZOOM; i++)
2526 gtk_toggle_button_set_active(
2527 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[i]), FALSE);
2530 gtk_toggle_button_set_active(
2531 GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[
2532 _zoom + (_curr_repo->double_size ? 1 : 0)]), TRUE);
2534 gtk_widget_show_all(dialog);
2536 mapman_update_state(NULL, &mapman_info);
2538 if(_curr_repo->type != REPOTYPE_NONE)
2540 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
2544 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
2546 _("NOTE: You must set a Map URI in the current repository in "
2547 "order to download maps."));
2550 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
2552 MapUpdateType update_type;
2553 static gint8 download_batch_id = INT8_MIN;
2555 if(gtk_toggle_button_get_active(
2556 GTK_TOGGLE_BUTTON(mapman_info.rad_delete)))
2557 update_type = MAP_UPDATE_DELETE;
2558 else if(gtk_toggle_button_get_active(
2559 GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite)))
2560 update_type = MAP_UPDATE_OVERWRITE;
2562 update_type = MAP_UPDATE_ADD;
2564 ++download_batch_id;
2565 if(gtk_toggle_button_get_active(
2566 GTK_TOGGLE_BUTTON(mapman_info.rad_by_route)))
2568 if(mapman_by_route(&mapman_info, update_type, download_batch_id))
2575 gdouble start_lat, start_lon, end_lat, end_lon;
2577 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
2578 start_lat = strdmstod(text, &error_check);
2579 if(text == error_check || start_lat < -90. || start_lat > 90.) {
2580 popup_error(dialog, _("Invalid Top-Left Latitude"));
2584 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
2585 start_lon = strdmstod(text, &error_check);
2586 if(text == error_check || start_lon < -180. || start_lon>180.) {
2587 popup_error(dialog, _("Invalid Top-Left Longitude"));
2591 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
2592 end_lat = strdmstod(text, &error_check);
2593 if(text == error_check || end_lat < -90. || end_lat > 90.) {
2594 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
2598 text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
2599 end_lon = strdmstod(text, &error_check);
2600 if(text == error_check || end_lon < -180. || end_lon > 180.) {
2601 popup_error(dialog,_("Invalid Bottom-Right Longitude"));
2605 if(mapman_by_area(start_lat, start_lon, end_lat, end_lon,
2606 &mapman_info, update_type, download_batch_id))
2611 gtk_widget_hide(dialog);
2613 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);