]> err.no Git - mapper/blob - src/map-repo.c
include dialogs.h
[mapper] / src / map-repo.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  * Copyright (C) 2006-2007 John Costigan.
6  *
7  * POI and GPS-Info code originally written by Cezary Jackiewicz.
8  *
9  * Default map data provided by http://www.openstreetmap.org/
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <config.h>
27
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <stddef.h>
33 #include <libintl.h>
34 #include <locale.h>
35 #include <math.h>
36 #include <gtk/gtk.h>
37 #include <libgnomevfs/gnome-vfs.h>
38
39 #include "hildon-mapper.h"
40
41 #include "utils.h"
42 #include "gps.h"
43 #include "map.h"
44 #include "latlon.h"
45 #include "route.h"
46 #include "settings.h"
47 #include "mapper-types.h"
48 #include "map-download.h"
49 #include "ui-common.h"
50 #include "dialogs.h"
51 #include "help.h"
52
53 #define MAP_REPO_LIST_URL "http://www.gnuite.com/nokia770/maemo-mapper/repos.txt"
54
55 typedef struct _RepoManInfo RepoManInfo;
56 struct _RepoManInfo {
57         GtkWidget *dialog;
58         GtkWidget *notebook;
59         GtkWidget *cmb_repos;
60         GList *repo_edits;
61 };
62
63 typedef struct _RepoEditInfo RepoEditInfo;
64 struct _RepoEditInfo {
65         gchar *name;
66         GtkWidget *txt_url;
67         GtkWidget *txt_cache_dir;
68         GtkWidget *num_dl_zoom_steps;
69         GtkWidget *num_view_zoom_steps;
70         GtkWidget *chk_double_size;
71         GtkWidget *chk_nextable;
72         GtkWidget *btn_browse;
73         BrowseInfo browse_info;
74 };
75
76 typedef struct _MapmanInfo MapmanInfo;
77 struct _MapmanInfo {
78         GtkWidget *dialog;
79         GtkWidget *notebook;
80         GtkWidget *tbl_area;
81
82         /* The "Setup" tab. */
83         GtkWidget *rad_download;
84         GtkWidget *rad_delete;
85         GtkWidget *chk_overwrite;
86         GtkWidget *rad_by_area;
87         GtkWidget *rad_by_route;
88         GtkWidget *num_route_radius;
89
90         /* The "Area" tab. */
91         GtkWidget *txt_topleft_lat;
92         GtkWidget *txt_topleft_lon;
93         GtkWidget *txt_botright_lat;
94         GtkWidget *txt_botright_lon;
95
96         /* The "Zoom" tab. */
97         GtkWidget *chk_zoom_levels[MAX_ZOOM];
98 };
99
100 void set_repo_type(RepoData * repo)
101 {
102 if (repo->url && *repo->url) {
103         gchar *url = g_utf8_strdown(repo->url, -1);
104
105         /* Determine type of repository. */
106         if (strstr(url, "service=wms"))
107                 repo->type = REPOTYPE_WMS;
108         else if (strstr(url, "%s"))
109                 repo->type = REPOTYPE_QUAD_QRST;
110         else if (strstr(url, "%0d"))
111                 repo->type = REPOTYPE_XYZ_INV;
112         else if (strstr(url, "%0s"))
113                 repo->type = REPOTYPE_QUAD_ZERO;
114         else
115                 repo->type = REPOTYPE_XYZ;
116
117         g_free(url);
118 } else
119         repo->type = REPOTYPE_NONE;
120 }
121
122 RepoData *
123 config_parse_repo(gchar * str)
124 {
125         /* Parse each part of a repo, delimited by newline characters:
126          * 1. name
127          * 2. url
128          * 3. cache_dir
129          * 4. dl_zoom_steps
130          * 5. view_zoom_steps
131          */
132 gchar *token, *error_check;
133
134 RepoData *rd = g_new0(RepoData, 1);
135
136 /* Parse name. */
137 token = strsep(&str, "\n\t");
138 if (token)
139         rd->name = g_strdup(token);
140
141 /* Parse URL format. */
142 token = strsep(&str, "\n\t");
143 if (token)
144         rd->url = g_strdup(token);
145
146 /* Parse cache dir. */
147 token = strsep(&str, "\n\t");
148 if (token)
149         rd->cache_dir = gnome_vfs_expand_initial_tilde(token);
150
151 /* Parse download zoom steps. */
152 token = strsep(&str, "\n\t");
153 if (!token || !*token || !(rd->dl_zoom_steps = atoi(token)))
154         rd->dl_zoom_steps = 2;
155
156 /* Parse view zoom steps. */
157 token = strsep(&str, "\n\t");
158 if (!token || !*token || !(rd->view_zoom_steps = atoi(token)))
159         rd->view_zoom_steps = 1;
160
161 /* Parse double-size. */
162 token = strsep(&str, "\n\t");
163 if (token)
164         rd->double_size = atoi(token);  /* Default is zero (FALSE) */
165
166 /* Parse next-able. */
167 token = strsep(&str, "\n\t");
168 if (!token || !*token
169     || (rd->nextable = strtol(token, &error_check, 10), token == str))
170                 rd->nextable = TRUE;
171
172 set_repo_type(rd);
173 return rd;
174 }
175
176 gboolean
177 repo_make_cache_dir(gchar * name, const gchar * cache_dir, GtkWidget * parent)
178 {
179 if (g_mkdir_with_parents(cache_dir, 0755)) {
180         /* Failed to create Map Cache directory. */
181         gchar buffer[BUFFER_SIZE];
182         g_snprintf(buffer, sizeof(buffer), "%s: %s",
183                  _("Unable to create cache directory for repository"), name);
184         popup_error(parent, buffer);
185         return FALSE;
186 }
187 return g_file_test(cache_dir, G_FILE_TEST_EXISTS);
188 }
189
190 gboolean 
191 repo_set_curr(RepoData * rd)
192 {
193 _curr_repo = rd;
194 return repo_make_cache_dir(rd->name, rd->cache_dir, _window);
195 }
196
197 static gboolean 
198 repoman_dialog_select(GtkWidget * widget, RepoManInfo * rmi)
199 {
200 gint curr_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
201 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi->notebook), curr_index);
202 return TRUE;
203 }
204
205 static gboolean 
206 repoman_dialog_browse(GtkWidget * widget, BrowseInfo * browse_info)
207 {
208 GtkWidget *dialog;
209
210 dialog = GTK_WIDGET(hildon_file_chooser_dialog_new
211        (GTK_WINDOW(browse_info->dialog),
212                 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER));
213
214 gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(dialog), TRUE);
215 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), gtk_entry_get_text(GTK_ENTRY(browse_info->txt)));
216
217 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(dialog))) {
218         gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
219         gtk_entry_set_text(GTK_ENTRY(browse_info->txt), filename);
220         g_free(filename);
221 }
222
223 gtk_widget_destroy(dialog);
224
225 return TRUE;
226 }
227
228 static gboolean 
229 repoman_dialog_rename(GtkWidget * widget, RepoManInfo * rmi)
230 {
231 GtkWidget *hbox;
232 GtkWidget *label;
233 GtkWidget *txt_name;
234 GtkWidget *dialog;
235
236 dialog = gtk_dialog_new_with_buttons(_("New Name"),
237                              GTK_WINDOW(rmi->dialog),
238                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
239                              GTK_RESPONSE_ACCEPT,
240                              GTK_STOCK_CANCEL,
241                              GTK_RESPONSE_REJECT, NULL);
242
243 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
244
245 gtk_box_pack_start(GTK_BOX(hbox), label = gtk_label_new(_("Name")), FALSE, FALSE, 0);
246 gtk_box_pack_start(GTK_BOX(hbox), txt_name = gtk_entry_new(), TRUE, TRUE, 0);
247
248 gtk_widget_show_all(dialog);
249
250 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
251         gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
252         RepoEditInfo *rei = g_list_nth_data(rmi->repo_edits, active);
253         g_free(rei->name);
254         rei->name = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name)));
255         gtk_combo_box_insert_text(GTK_COMBO_BOX(rmi->cmb_repos), active, g_strdup(rei->name));
256         gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), active);
257         gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active + 1);
258         break;
259 }
260
261 gtk_widget_destroy(dialog);
262 return TRUE;
263 }
264
265 static gboolean 
266 repoman_dialog_delete(GtkWidget * widget, RepoManInfo * rmi)
267 {
268 gchar buffer[100];
269 GtkWidget *confirm;
270 gint active = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi->cmb_repos));
271
272 if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtk_combo_box_get_model(GTK_COMBO_BOX(rmi->cmb_repos))), NULL) <= 1) {
273         popup_error(rmi->dialog, _("Cannot delete the last repository - there must be at lease one repository."));
274         return TRUE;
275 }
276
277 g_snprintf(buffer, sizeof(buffer), "%s:\n%s\n",
278          _("Confirm delete of repository"),
279          gtk_combo_box_get_active_text(GTK_COMBO_BOX(rmi->cmb_repos)));
280 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
281
282 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
283         gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), active);
284         gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), active);
285         rmi->repo_edits = g_list_remove_link(rmi->repo_edits, g_list_nth(rmi->repo_edits, active));
286         gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), MAX(0, active - 1));
287 }
288
289 gtk_widget_destroy(confirm);
290
291 return TRUE;
292 }
293
294 static RepoEditInfo *
295 repoman_dialog_add_repo(RepoManInfo * rmi, gchar * name)
296 {
297 GtkWidget *vbox;
298 GtkWidget *table;
299 GtkWidget *label;
300 GtkWidget *hbox;
301 RepoEditInfo *rei = g_new(RepoEditInfo, 1);
302
303 rei->name = name;
304
305 /* Maps page. */
306 gtk_notebook_append_page(GTK_NOTEBOOK(rmi->notebook), vbox = gtk_vbox_new(FALSE, 4), gtk_label_new(name));
307
308 gtk_box_pack_start(GTK_BOX(vbox), table = gtk_table_new(2, 2, FALSE), FALSE, FALSE, 0);
309 /* Map download URI. */
310 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("URL Format")), 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
311 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
312 gtk_table_attach(GTK_TABLE(table), rei->txt_url = gtk_entry_new(), 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
313
314 /* Map Directory. */
315 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Cache Dir.")), 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
316 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
317 gtk_table_attach(GTK_TABLE(table), hbox = gtk_hbox_new(FALSE, 4), 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
318 gtk_box_pack_start(GTK_BOX(hbox), rei->txt_cache_dir = gtk_entry_new(), TRUE, TRUE, 0);
319 gtk_box_pack_start(GTK_BOX(hbox), rei->btn_browse = gtk_button_new_with_label(_("Browse...")), FALSE, FALSE, 0);
320
321 /* Initialize cache dir */
322 {
323         gchar *cache_base = gnome_vfs_expand_initial_tilde(REPO_DEFAULT_CACHE_BASE);
324         gchar *cache_dir = gnome_vfs_uri_make_full_from_relative(cache_base, name);
325         gtk_entry_set_text(GTK_ENTRY(rei->txt_cache_dir), cache_dir);
326         g_free(cache_dir);
327         g_free(cache_base);
328 }
329
330 gtk_box_pack_start(GTK_BOX(vbox), table = gtk_table_new(3, 2, FALSE), FALSE, FALSE, 0);
331
332 /* Download Zoom Steps. */
333 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("Download Zoom Steps")), 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
334 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
335 gtk_table_attach(GTK_TABLE(table), rei->num_dl_zoom_steps = hildon_controlbar_new(), 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 2, 4);
336 hildon_controlbar_set_range(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1, 4);
337 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), REPO_DEFAULT_DL_ZOOM_STEPS);
338 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), 1);
339
340 /* Download Zoom Steps. */
341 gtk_table_attach(GTK_TABLE(table), label = gtk_label_new(_("View Zoom Steps")), 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
342 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
343 gtk_table_attach(GTK_TABLE(table), rei->num_view_zoom_steps = hildon_controlbar_new(), 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 2, 4);
344 hildon_controlbar_set_range(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1, 4);
345 hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps), REPO_DEFAULT_VIEW_ZOOM_STEPS);
346 force_min_visible_bars(HILDON_CONTROLBAR(rei->num_view_zoom_steps), 1);
347
348 gtk_table_attach(GTK_TABLE(table), label = gtk_vseparator_new(), 2, 3, 0, 2, GTK_FILL, GTK_FILL, 4, 4);
349
350 /* Double-size. */
351 gtk_table_attach(GTK_TABLE(table), rei->chk_double_size = gtk_check_button_new_with_label(_("Double Pixels")), 3, 4, 0, 1, GTK_FILL, GTK_FILL, 0, 4);
352 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_double_size), FALSE);
353
354 /* Next-able */
355 gtk_table_attach(GTK_TABLE(table), rei->chk_nextable = gtk_check_button_new_with_label(_("Next-able")), 3, 4, 1, 2, GTK_FILL, GTK_FILL, 0, 4);
356 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_nextable), TRUE);
357
358 rmi->repo_edits = g_list_append(rmi->repo_edits, rei);
359
360 /* Connect signals. */
361 rei->browse_info.dialog = rmi->dialog;
362 rei->browse_info.txt = rei->txt_cache_dir;
363 g_signal_connect(G_OBJECT(rei->btn_browse), "clicked", G_CALLBACK(repoman_dialog_browse), &rei->browse_info);
364
365 gtk_widget_show_all(vbox);
366
367 gtk_combo_box_append_text(GTK_COMBO_BOX(rmi->cmb_repos), name);
368 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos),
369         gtk_tree_model_iter_n_children(GTK_TREE_MODEL(gtk_combo_box_get_model(GTK_COMBO_BOX (rmi->cmb_repos))), NULL) - 1);
370
371 return rei;
372 }
373
374 static gboolean 
375 repoman_dialog_new(GtkWidget * widget, RepoManInfo * rmi)
376 {
377 GtkWidget *hbox;
378 GtkWidget *label;
379 GtkWidget *txt_name;
380 GtkWidget *dialog;
381
382 dialog = gtk_dialog_new_with_buttons(_("New Repository"),
383                                      GTK_WINDOW(rmi->dialog),
384                                      GTK_DIALOG_MODAL, GTK_STOCK_OK,
385                                      GTK_RESPONSE_ACCEPT,
386                                      GTK_STOCK_CANCEL,
387                                      GTK_RESPONSE_REJECT, NULL);
388
389 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
390
391 gtk_box_pack_start(GTK_BOX(hbox), label = gtk_label_new(_("Name")), FALSE, FALSE, 0);
392 gtk_box_pack_start(GTK_BOX(hbox), txt_name = gtk_entry_new(), TRUE, TRUE, 0);
393
394 gtk_widget_show_all(dialog);
395
396 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
397                 repoman_dialog_add_repo(rmi, g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_name))));
398         break;
399 }
400
401 gtk_widget_destroy(dialog);
402
403 return TRUE;
404 }
405
406 static gboolean
407 repoman_reset(GtkWidget * widget, RepoManInfo * rmi)
408 {
409 GtkWidget *confirm;
410
411 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
412                 _("Replace all repositories with the default repository?"));
413
414 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
415         /* First, delete all existing repositories. */
416         while (rmi->repo_edits) {
417                 gtk_combo_box_remove_text(GTK_COMBO_BOX(rmi->cmb_repos), 0);
418                         gtk_notebook_remove_page(GTK_NOTEBOOK(rmi->notebook), 0);
419                         rmi->repo_edits = g_list_remove_link(rmi->repo_edits, g_list_first(rmi->repo_edits));
420                 }
421
422         /* Now, add the default repository. */
423         repoman_dialog_add_repo(rmi, REPO_DEFAULT_NAME);
424         gtk_entry_set_text(GTK_ENTRY(((RepoEditInfo *) rmi->repo_edits->data)->txt_url), REPO_DEFAULT_MAP_URI);
425
426         gtk_combo_box_set_active(GTK_COMBO_BOX(rmi->cmb_repos), 0);
427 }
428 gtk_widget_destroy(confirm);
429
430 return TRUE;
431 }
432
433 static gboolean 
434 repoman_download(GtkWidget * widget, RepoManInfo * rmi)
435 {
436 GtkWidget *confirm;
437
438 confirm = hildon_note_new_confirmation(GTK_WINDOW(rmi->dialog),
439                                        _("Mapper will now download and add a list of "
440                                         "possibly-duplicate repositories from the internet.  "
441                                         "Continue?"));
442
443 if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
444         gchar *bytes;
445         gchar *head;
446         gchar *tail;
447         gint size;
448         GnomeVFSResult vfs_result;
449
450         /* Get repo config file from www.gnuite.com. */
451         if (GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(MAP_REPO_LIST_URL, &size, &bytes))) {
452                 popup_error(rmi->dialog,
453                             _("An error occurred while retrieving the repositories.  "
454                              "The web service may be temporarily down."));
455                 g_printerr("Error while download repositories: %s\n", gnome_vfs_result_to_string(vfs_result));
456         } else {
457                 /* Parse each line as a reposotory. */
458                 for (head = bytes; head && *head; head = tail) {
459                         RepoData *rd;
460                         RepoEditInfo *rei;
461                         tail = strchr(head, '\n');
462                         *tail++ = '\0';
463                         rd = config_parse_repo(head);
464                         rei = repoman_dialog_add_repo(rmi, g_strdup(rd->name));
465                         /* Initialize fields with data from the RepoData object. */
466                         gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
467                         gtk_entry_set_text(GTK_ENTRY(rei->txt_cache_dir), rd->cache_dir);
468                         hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), rd->dl_zoom_steps);
469                         hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps), rd->view_zoom_steps);
470                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_double_size), rd->double_size);
471                         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_nextable), rd->nextable);
472                 }
473                 g_free(bytes);
474         }
475 }
476 gtk_widget_destroy(confirm);
477
478 return TRUE;
479 }
480
481 gboolean 
482 repoman_dialog()
483 {
484 RepoManInfo rmi;
485 GtkWidget *hbox;
486 GtkWidget *btn_rename;
487 GtkWidget *btn_delete;
488 GtkWidget *btn_new;
489 GtkWidget *btn_reset;
490 GtkWidget *btn_download;
491 guint i, curr_repo_index = 0;
492 GList *curr;
493
494 rmi.dialog = gtk_dialog_new_with_buttons(_("Manage Repositories"),
495                                          GTK_WINDOW(_window),
496                                          GTK_DIALOG_MODAL, GTK_STOCK_OK,
497                                          GTK_RESPONSE_ACCEPT, NULL);
498
499 help_dialog_help_enable(GTK_DIALOG(rmi.dialog), HELP_ID_REPOMAN);
500
501 /* Reset button. */
502 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(rmi.dialog)->action_area),
503                   btn_reset = gtk_button_new_with_label(_("Reset...")));
504 g_signal_connect(G_OBJECT(btn_reset), "clicked", G_CALLBACK(repoman_reset), &rmi);
505
506 /* Download button. */
507 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(rmi.dialog)->action_area),
508                   btn_download = gtk_button_new_with_label(_("Download...")));
509 g_signal_connect(G_OBJECT(btn_download), "clicked", G_CALLBACK(repoman_download), &rmi);
510
511 /* Cancel button. */
512 gtk_dialog_add_button(GTK_DIALOG(rmi.dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
513
514 hbox = gtk_hbox_new(FALSE, 4);
515
516 gtk_box_pack_start(GTK_BOX(hbox), rmi.cmb_repos = gtk_combo_box_new_text(), TRUE, TRUE, 4);
517
518 gtk_box_pack_start(GTK_BOX(hbox), gtk_vseparator_new(), FALSE, FALSE, 4);
519 gtk_box_pack_start(GTK_BOX(hbox), btn_rename = gtk_button_new_with_label(_("Rename...")), FALSE, FALSE, 4);
520 gtk_box_pack_start(GTK_BOX(hbox), btn_delete = gtk_button_new_with_label(_("Delete...")), FALSE, FALSE, 4);
521 gtk_box_pack_start(GTK_BOX(hbox), btn_new = gtk_button_new_with_label(_("New...")), FALSE, FALSE, 4);
522
523 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox), hbox, FALSE, FALSE, 4);
524 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox), gtk_hseparator_new(), TRUE, TRUE, 4);
525 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox), rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
526
527 gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
528 gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
529
530 rmi.repo_edits = NULL;
531
532 /* Populate combo box and pages in notebook. */
533 for (i = 0, curr = _repo_list; curr; curr = curr->next, i++) {
534         RepoData *rd = (RepoData *) curr->data;
535         RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
536
537         /* Initialize fields with data from the RepoData object. */
538         gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
539         gtk_entry_set_text(GTK_ENTRY(rei->txt_cache_dir), rd->cache_dir);
540         hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps), rd->dl_zoom_steps);
541         hildon_controlbar_set_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps), rd->view_zoom_steps);
542         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_double_size), rd->double_size);
543         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rei->chk_nextable), rd->nextable);
544         if (rd == _curr_repo)
545                 curr_repo_index = i;
546 }
547
548 /* Connect signals. */
549 g_signal_connect(G_OBJECT(btn_rename), "clicked", G_CALLBACK(repoman_dialog_rename), &rmi);
550 g_signal_connect(G_OBJECT(btn_delete), "clicked", G_CALLBACK(repoman_dialog_delete), &rmi);
551 g_signal_connect(G_OBJECT(btn_new), "clicked", G_CALLBACK(repoman_dialog_new), &rmi);
552 g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed", G_CALLBACK(repoman_dialog_select), &rmi);
553 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
554 gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
555
556 gtk_widget_show_all(rmi.dialog);
557
558 while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(rmi.dialog))) {
559         /* Iterate through repos and verify each. */
560         gboolean verified = TRUE;
561         gint i;
562         GList *curr;
563         gchar *old_curr_repo_name = _curr_repo->name;
564
565         for (i = 0, curr = rmi.repo_edits; verified && curr; curr = curr->next, i++) {
566                 RepoEditInfo *rei = curr->data;
567                 gchar *expanded = gnome_vfs_expand_initial_tilde(gtk_entry_get_text(GTK_ENTRY(rei->txt_cache_dir)));
568                 verified = repo_make_cache_dir(rei->name, expanded,     rmi.dialog);
569                 g_free(expanded);
570         }
571         if (!verified) {
572                 gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i - 1);
573                 continue;
574         }
575
576         /* But keep the repo list in memory, in case downloads are using it. */
577         _repo_list = NULL;
578
579         /* Write new _repo_list. */
580         curr_repo_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi.cmb_repos));
581         _curr_repo = NULL;
582         for (i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++) {
583                 RepoEditInfo *rei = curr->data;
584                 RepoData *rd = g_new(RepoData, 1);
585                 rd->name = g_strdup(rei->name);
586                 rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
587                 rd->cache_dir = gnome_vfs_expand_initial_tilde(gtk_entry_get_text(GTK_ENTRY(rei->txt_cache_dir)));
588                 rd->dl_zoom_steps = hildon_controlbar_get_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
589                 rd->view_zoom_steps = hildon_controlbar_get_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps));
590                 rd->double_size = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rei->chk_double_size));
591                 rd->nextable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rei->chk_nextable));
592                 set_repo_type(rd);
593
594                 _repo_list = g_list_append(_repo_list, rd);
595
596                 if (!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
597                         repo_set_curr(rd);
598                 else if (i == curr_repo_index)
599                         repo_set_curr(rd);
600         }
601         if (!_curr_repo)
602                         repo_set_curr((RepoData *) g_list_first(_repo_list)->data);
603
604         menu_maps_add_repos();
605         config_save_repo();
606         break;
607 }
608
609 gtk_widget_hide(rmi.dialog);    /* Destroying causes a crash (!?!?!??!) */
610 map_set_zoom(_zoom);    /* make sure we're at an appropriate zoom level. */
611 return TRUE;
612 }
613
614 static gboolean
615 mapman_by_area(gfloat start_lat, gfloat start_lon,
616                gfloat end_lat, gfloat end_lon, MapmanInfo * mapman_info,
617                gboolean is_deleting, gboolean is_overwriting)
618 {
619 guint start_unitx, start_unity, end_unitx, end_unity;
620 guint num_maps = 0;
621 guint i;
622 gchar buffer[80];
623 GtkWidget *confirm;
624
625 latlon2unit(start_lat, start_lon, start_unitx, start_unity);
626 latlon2unit(end_lat, end_lon, end_unitx, end_unity);
627
628 /* Swap if they specified flipped lats or lons. */
629 if (start_unitx > end_unitx) {
630         guint swap = start_unitx;
631         start_unitx = end_unitx;
632         end_unitx = swap;
633 }
634 if (start_unity > end_unity) {
635         guint swap = start_unity;
636         start_unity = end_unity;
637         end_unity = swap;
638 }
639
640 /* First, get the number of maps to download. */
641 for (i = 0; i < MAX_ZOOM; i++) {
642         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
643                 guint start_tilex, start_tiley, end_tilex, end_tiley;
644                 start_tilex = unit2ztile(start_unitx, i);
645                 start_tiley = unit2ztile(start_unity, i);
646                 end_tilex = unit2ztile(end_unitx, i);
647                 end_tiley = unit2ztile(end_unity, i);
648                 num_maps += (end_tilex - start_tilex + 1) * (end_tiley - start_tiley + 1);
649                 }
650 }
651
652 if (is_deleting) {
653         g_snprintf(buffer, sizeof(buffer), "%s %d %s", _("Confirm DELETION of"), num_maps, _("maps "));
654 } else {
655         g_snprintf(buffer, sizeof(buffer), "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
656                 num_maps, _("maps"), _("up to about"), num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
657 }
658 confirm = hildon_note_new_confirmation(GTK_WINDOW(mapman_info->dialog), buffer);
659
660 if (GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm))) {
661         gtk_widget_destroy(confirm);
662         return FALSE;
663 }
664
665 for (i = 0; i < MAX_ZOOM; i++) {
666         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
667                 guint start_tilex, start_tiley, end_tilex, end_tiley;
668                 guint tilex, tiley;
669                 start_tilex = unit2ztile(start_unitx, i);
670                 start_tiley = unit2ztile(start_unity, i);
671                 end_tilex = unit2ztile(end_unitx, i);
672                 end_tiley = unit2ztile(end_unity, i);
673
674                 for (tiley = start_tiley; tiley <= end_tiley; tiley++)
675                         for (tilex = start_tilex; tilex <= end_tilex; tilex++)
676                                 map_initiate_download(tilex, tiley, i, is_deleting ? 0 : (is_overwriting ?
677                                                          -INITIAL_DOWNLOAD_RETRIES : INITIAL_DOWNLOAD_RETRIES));
678         }
679 }
680 gtk_widget_destroy(confirm);
681 return TRUE;
682 }
683
684 static gboolean
685 mapman_by_route(MapmanInfo * mapman_info, gboolean is_deleting, gboolean is_overwriting)
686 {
687 GtkWidget *confirm;
688 guint prev_tilex, prev_tiley, num_maps = 0, i;
689 Point *curr;
690 gchar buffer[80];
691 guint radius = hildon_number_editor_get_value(HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
692
693 /* First, get the number of maps to download. */
694 for (i = 0; i < MAX_ZOOM; i++) {
695         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
696                 prev_tilex = 0;
697                 prev_tiley = 0;
698
699                 for (curr = _route.head - 1; curr++ != _route.tail;) {
700                         if (curr->unity) {
701                                 guint tilex = unit2ztile(curr->unitx, i);
702                                 guint tiley = unit2ztile(curr->unity, i);
703                                 if (tilex != prev_tilex || tiley != prev_tiley) {
704                                         if (prev_tiley)
705                                                 num_maps += (abs((gint) tilex - prev_tilex) + 1) * (abs((gint) tiley - prev_tiley) + 1) - 1;
706                                         prev_tilex = tilex;
707                                         prev_tiley = tiley;
708                                 }
709                         }
710                 }
711         }
712 }
713 num_maps *= 0.625 * pow(radius + 1, 1.85);
714
715 if (is_deleting) {
716         g_snprintf(buffer, sizeof(buffer), "%s %s %d %s",
717                  _("Confirm DELETION of"), _("about"),
718                  num_maps, _("maps "));
719 } else {
720         g_snprintf(buffer, sizeof(buffer),
721                  "%s %s %d %s\n(%s %.2f MB)\n",
722                  _("Confirm download of"), _("about"), num_maps,
723                  _("maps"), _("up to about"),
724                  num_maps * (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
725 }
726 confirm = hildon_note_new_confirmation(GTK_WINDOW(mapman_info->dialog), buffer);
727
728 if (GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm))) {
729         gtk_widget_destroy(confirm);
730         return FALSE;
731 }
732
733 /* Now, do the actual download. */
734 for (i = 0; i < MAX_ZOOM; i++) {
735         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
736                 prev_tilex = 0;
737                 prev_tiley = 0;
738
739                 for (curr = _route.head - 1; curr++ != _route.tail;) {
740                         if (curr->unity) {
741                                 guint tilex = unit2ztile(curr->unitx, i);
742                                 guint tiley = unit2ztile(curr->unity, i);
743                                 if (tilex != prev_tilex || tiley != prev_tiley) {
744                                         guint minx, miny, maxx, maxy, x, y;
745                                         if (prev_tiley != 0) {
746                                                 minx = MIN(tilex, prev_tilex) - radius;
747                                                 miny = MIN(tiley, prev_tiley) - radius;
748                                                 maxx = MAX(tilex, prev_tilex) + radius;
749                                                 maxy = MAX(tiley, prev_tiley) + radius;
750                                         } else {
751                                                 minx = tilex - radius;
752                                                 miny = tiley - radius;
753                                                 maxx = tilex + radius;
754                                                 maxy = tiley + radius;
755                                         }
756                                         for (x = minx; x <= maxx; x++)
757                                                 for (y = miny; y <= maxy; y++)
758                                                         map_initiate_download(x, y, i, is_deleting ? 0
759                                                              : (is_overwriting ? -INITIAL_DOWNLOAD_RETRIES : INITIAL_DOWNLOAD_RETRIES));
760                                         prev_tilex = tilex;
761                                         prev_tiley = tiley;
762                                 }
763                         }
764                 }
765         }
766 }
767 _route_dl_radius = radius;
768 gtk_widget_destroy(confirm);
769 return TRUE;
770 }
771
772 static void 
773 mapman_clear(GtkWidget * widget, MapmanInfo * mapman_info)
774 {
775 guint i;
776
777 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook))) {
778         /* This is the second page (the "Zoom" page) - clear the checks. */
779         for (i = 0; i < MAX_ZOOM; i++)
780                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]), FALSE);
781 } else {
782         /* This is the first page (the "Area" page) - clear the text fields. */
783         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
784         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
785         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
786         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
787 }
788 }
789
790 static void 
791 mapman_update_state(GtkWidget * widget, MapmanInfo * mapman_info)
792 {
793 gtk_widget_set_sensitive(mapman_info->chk_overwrite,
794          gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
795
796         if (gtk_toggle_button_get_active
797             (GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
798                 gtk_widget_show(mapman_info->tbl_area);
799         else if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook))
800                  == 3)
801                 gtk_widget_hide(mapman_info->tbl_area);
802
803         gtk_widget_set_sensitive(mapman_info->num_route_radius,
804                                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
805                                                               (mapman_info->rad_by_route)));
806 }
807
808 gboolean menu_cb_mapman(GtkAction * action)
809 {
810         GtkWidget *dialog;
811         GtkWidget *vbox;
812         GtkWidget *hbox;
813         GtkWidget *table;
814         GtkWidget *label;
815         GtkWidget *button;
816         GtkWidget *lbl_gps_lat;
817         GtkWidget *lbl_gps_lon;
818         GtkWidget *lbl_center_lat;
819         GtkWidget *lbl_center_lon;
820         MapmanInfo mapman_info;
821         gchar buffer[80];
822         gfloat lat, lon;
823         guint i;
824
825         mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(_("Manage Maps"), GTK_WINDOW(_window),
826                                         GTK_DIALOG_MODAL, GTK_STOCK_OK,
827                                         GTK_RESPONSE_ACCEPT, NULL);
828
829         help_dialog_help_enable(GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN);
830
831         /* Clear button. */
832         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
833                           button = gtk_button_new_with_label(_("Clear")));
834         g_signal_connect(G_OBJECT(button), "clicked",
835                          G_CALLBACK(mapman_clear), &mapman_info);
836
837         /* Cancel button. */
838         gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
839
840         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
841                            mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
842
843         /* Setup page. */
844         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
845                                  vbox = gtk_vbox_new(FALSE, 2),
846                                  label = gtk_label_new(_("Setup")));
847         gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(mapman_info.notebook),
848                                            vbox, FALSE, FALSE, GTK_PACK_START);
849
850         gtk_box_pack_start(GTK_BOX(vbox),
851                            hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 0);
852         gtk_box_pack_start(GTK_BOX(hbox),
853                            mapman_info.rad_download = gtk_radio_button_new_with_label(NULL, _("Download Maps")), FALSE, FALSE, 0);
854         gtk_box_pack_start(GTK_BOX(hbox), label =
855                            gtk_alignment_new(0.f, 0.5f, 0.f, 0.f), FALSE, FALSE,
856                            0);
857         gtk_container_add(GTK_CONTAINER(label), mapman_info.chk_overwrite =
858                           gtk_check_button_new_with_label(_("Overwrite"))),
859             gtk_box_pack_start(GTK_BOX(vbox), mapman_info.rad_delete =
860                                gtk_radio_button_new_with_label_from_widget
861                                (GTK_RADIO_BUTTON(mapman_info.rad_download),
862                                 _("Delete Maps")), FALSE, FALSE, 0);
863
864         gtk_box_pack_start(GTK_BOX(vbox),
865                            gtk_hseparator_new(), FALSE, FALSE, 0);
866
867         gtk_box_pack_start(GTK_BOX(vbox),
868                            mapman_info.rad_by_area
869                            = gtk_radio_button_new_with_label(NULL, _("By Area (see tab)")), FALSE, FALSE, 0);
870         gtk_box_pack_start(GTK_BOX(vbox), hbox =
871                            gtk_hbox_new(FALSE, 4), FALSE, FALSE, 0);
872         gtk_box_pack_start(GTK_BOX(hbox), mapman_info.rad_by_route =
873                            gtk_radio_button_new_with_label_from_widget
874                            (GTK_RADIO_BUTTON(mapman_info.rad_by_area),
875                             _("Along Route - Radius (tiles):")), FALSE, FALSE,
876                            0);
877         gtk_widget_set_sensitive(mapman_info.rad_by_route,
878                                  _route.head != _route.tail);
879         gtk_box_pack_start(GTK_BOX(hbox), mapman_info.num_route_radius =
880                            hildon_number_editor_new(0, 100), FALSE, FALSE, 0);
881         hildon_number_editor_set_value(HILDON_NUMBER_EDITOR
882                                        (mapman_info.num_route_radius),
883                                        _route_dl_radius);
884
885         /* Zoom page. */
886         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
887                                  table = gtk_table_new(5, 5, FALSE),
888                                  label = gtk_label_new(_("Zoom")));
889         gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(mapman_info.notebook),
890                                            table, FALSE, FALSE, GTK_PACK_START);
891         gtk_table_attach(GTK_TABLE(table), label =
892                          gtk_label_new(_
893                                        ("Zoom Levels to Download: (0 = most detail)")),
894                          0, 4, 0, 1, GTK_FILL, 0, 4, 0);
895         gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
896         for (i = 0; i < MAX_ZOOM; i++) {
897                 g_snprintf(buffer, sizeof(buffer), "%d", i);
898                 gtk_table_attach(GTK_TABLE(table),
899                                  mapman_info.chk_zoom_levels[i]
900                                  = gtk_check_button_new_with_label(buffer),
901                                  i % 4, i % 4 + 1, i / 4 + 1, i / 4 + 2,
902                                  GTK_EXPAND | GTK_FILL, 0, 4, 0);
903         }
904
905         /* Area page. */
906         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
907                                  mapman_info.tbl_area =
908                                  gtk_table_new(3, 4, FALSE), label =
909                                  gtk_label_new(_("Area")));
910
911         /* Label Columns. */
912         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
913                          label = gtk_label_new(_("Latitude")),
914                          1, 2, 0, 1, GTK_FILL, 0, 4, 0);
915         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
916         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
917                          label = gtk_label_new(_("Longitude")),
918                          2, 3, 0, 1, GTK_FILL, 0, 4, 0);
919         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
920
921         /* GPS. */
922         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
923                          label = gtk_label_new(_("GPS Location")),
924                          0, 1, 1, 2, GTK_FILL, 0, 4, 0);
925         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
926         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
927                          lbl_gps_lat = gtk_label_new(""),
928                          1, 2, 1, 2, GTK_FILL, 0, 4, 0);
929         gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
930         gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
931         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
932                          lbl_gps_lon = gtk_label_new(""),
933                          2, 3, 1, 2, GTK_FILL, 0, 4, 0);
934         gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
935         gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
936
937         /* Center. */
938         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
939                          label = gtk_label_new(_("View Center")),
940                          0, 1, 2, 3, GTK_FILL, 0, 4, 0);
941         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
942         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
943                          lbl_center_lat = gtk_label_new(""),
944                          1, 2, 2, 3, GTK_FILL, 0, 4, 0);
945         gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
946         gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
947         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
948                          lbl_center_lon = gtk_label_new(""),
949                          2, 3, 2, 3, GTK_FILL, 0, 4, 0);
950         gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
951         gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
952
953         /* default values for Top Left and Bottom Right are defined by the
954          * rectangle of the current and the previous Center */
955
956         /* Top Left. */
957         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
958                          label = gtk_label_new(_("Top-Left")),
959                          0, 1, 3, 4, GTK_FILL, 0, 4, 0);
960         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
961         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
962                          mapman_info.txt_topleft_lat = gtk_entry_new(),
963                          1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 4, 0);
964         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
965         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
966                          mapman_info.txt_topleft_lon = gtk_entry_new(),
967                          2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 4, 0);
968         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
969
970         /* Bottom Right. */
971         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
972                          label = gtk_label_new(_("Bottom-Right")),
973                          0, 1, 4, 5, GTK_FILL, 0, 4, 0);
974         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
975         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
976                          mapman_info.txt_botright_lat = gtk_entry_new(),
977                          1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 4, 0);
978         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
979         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
980                          mapman_info.txt_botright_lon = gtk_entry_new(),
981                          2, 3, 4, 5, GTK_EXPAND | GTK_FILL, 0, 4, 0);
982         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
983
984 #if defined(WITH_DEVICE_770) && !defined(WITH_HILDON_NEW)
985         /* Set hildon input hints */
986         g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
987                      HILDON_INPUT_MODE_HINT,
988                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
989         g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
990                      HILDON_INPUT_MODE_HINT,
991                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
992         g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
993                      HILDON_INPUT_MODE_HINT,
994                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
995         g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
996                      HILDON_INPUT_MODE_HINT,
997                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
998 #endif
999
1000         /* Default action is to download by area. */
1001         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
1002
1003         /* Initialize fields.  Do no use g_ascii_formatd; these strings will be
1004          * output (and parsed) as locale-dependent. */
1005
1006         g_snprintf(buffer, sizeof(buffer), "%.06f", _gps->data.lat);
1007         gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
1008         g_snprintf(buffer, sizeof(buffer), "%.06f", _gps->data.lon);
1009         gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
1010
1011         unit2latlon(_center.unitx, _center.unity, lat, lon);
1012         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1013         gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
1014         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1015         gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
1016
1017         /* Initialize to the bounds of the screen. */
1018         unit2latlon(x2unit(0), y2unit(0), lat, lon);
1019         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1020         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
1021         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1022         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
1023
1024         unit2latlon(x2unit(_screen_width_pixels), y2unit(_screen_height_pixels), lat, lon);
1025         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1026         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
1027         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1028         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
1029
1030         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[_zoom]), TRUE);
1031
1032         gtk_widget_show_all(dialog);
1033
1034         mapman_update_state(NULL, &mapman_info);
1035
1036         /* Connect signals. */
1037         if (_curr_repo->type != REPOTYPE_NONE) {
1038                 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1039                 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
1040         } else {
1041                 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
1042                 popup_error(dialog, _("NOTE: You must set a Map URI in the current repository in order to download maps."));
1043         }
1044
1045         g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1046         g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1047         g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1048
1049         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
1050                 gboolean is_deleting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.rad_delete));
1051                 gboolean is_overwriting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite));
1052                 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.rad_by_route))) {
1053                         if (mapman_by_route(&mapman_info, is_deleting, is_overwriting))
1054                                 break;
1055                 } else {
1056                         const gchar *text;
1057                         gchar *error_check;
1058                         gfloat start_lat, start_lon, end_lat, end_lon;
1059
1060                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
1061                         start_lat = strtof(text, &error_check);
1062                         if (text == error_check || start_lat < -90.f || start_lat > 90.f) {
1063                                 popup_error(dialog, _("Invalid Top-Left Latitude"));
1064                                 continue;
1065                         }
1066
1067                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
1068                         start_lon = strtof(text, &error_check);
1069                         if (text == error_check || start_lon < -180.f || start_lon > 180.f) {
1070                                 popup_error(dialog, _("Invalid Top-Left Longitude"));
1071                                 continue;
1072                         }
1073
1074                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
1075                         end_lat = strtof(text, &error_check);
1076                         if (text == error_check || end_lat < -90.f || end_lat > 90.f) {
1077                                 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
1078                                 continue;
1079                         }
1080
1081                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
1082                         end_lon = strtof(text, &error_check);
1083                         if (text == error_check || end_lon < -180.f || end_lon > 180.f) {
1084                                 popup_error(dialog, _("Invalid Bottom-Right Longitude"));
1085                                 continue;
1086                         }
1087
1088                         if (mapman_by_area(start_lat, start_lon, end_lat, end_lon, &mapman_info, is_deleting, is_overwriting))
1089                                 break;
1090                 }
1091         }
1092
1093         gtk_widget_hide(dialog);        /* Destroying causes a crash (!?!?!??!) */
1094
1095         return TRUE;
1096 }