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