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