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