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