]> err.no Git - mapper/blob - src/map-repo.c
Use globaly set _GNU_SOURCE
[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                                                _("Maemo 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                                     _
531                                     ("An error occurred while retrieving the repositories.  "
532                                      "The web service may be temporarily down."));
533                         g_printerr("Error while download repositories: %s\n",
534                                    gnome_vfs_result_to_string(vfs_result));
535                 }
536                 /* Parse each line as a reposotory. */
537                 else {
538                         for (head = bytes; head && *head; head = tail) {
539                                 RepoData *rd;
540                                 RepoEditInfo *rei;
541                                 tail = strchr(head, '\n');
542                                 *tail++ = '\0';
543                                 rd = config_parse_repo(head);
544                                 rei =
545                                     repoman_dialog_add_repo(rmi,
546                                                             g_strdup(rd->name));
547                                 /* Initialize fields with data from the RepoData object. */
548                                 gtk_entry_set_text(GTK_ENTRY(rei->txt_url),
549                                                    rd->url);
550                                 gtk_entry_set_text(GTK_ENTRY
551                                                    (rei->txt_cache_dir),
552                                                    rd->cache_dir);
553                                 hildon_controlbar_set_value(HILDON_CONTROLBAR
554                                                             (rei->
555                                                              num_dl_zoom_steps),
556                                                             rd->dl_zoom_steps);
557                                 hildon_controlbar_set_value(HILDON_CONTROLBAR
558                                                             (rei->
559                                                              num_view_zoom_steps),
560                                                             rd->
561                                                             view_zoom_steps);
562                                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
563                                                              (rei->
564                                                               chk_double_size),
565                                                              rd->double_size);
566                                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
567                                                              (rei->
568                                                               chk_nextable),
569                                                              rd->nextable);
570                         }
571                         g_free(bytes);
572                 }
573         }
574         gtk_widget_destroy(confirm);
575
576         return TRUE;
577 }
578
579 gboolean 
580 repoman_dialog()
581 {
582         RepoManInfo rmi;
583         GtkWidget *hbox;
584         GtkWidget *btn_rename;
585         GtkWidget *btn_delete;
586         GtkWidget *btn_new;
587         GtkWidget *btn_reset;
588         GtkWidget *btn_download;
589         guint i, curr_repo_index = 0;
590         GList *curr;
591
592         rmi.dialog = gtk_dialog_new_with_buttons(_("Manage Repositories"),
593                                                  GTK_WINDOW(_window),
594                                                  GTK_DIALOG_MODAL, GTK_STOCK_OK,
595                                                  GTK_RESPONSE_ACCEPT, NULL);
596
597         help_dialog_help_enable(GTK_DIALOG(rmi.dialog), HELP_ID_REPOMAN);
598
599         /* Reset button. */
600         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(rmi.dialog)->action_area),
601                           btn_reset = gtk_button_new_with_label(_("Reset...")));
602         g_signal_connect(G_OBJECT(btn_reset), "clicked",
603                          G_CALLBACK(repoman_reset), &rmi);
604
605         /* Download button. */
606         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(rmi.dialog)->action_area),
607                           btn_download =
608                           gtk_button_new_with_label(_("Download...")));
609         g_signal_connect(G_OBJECT(btn_download), "clicked",
610                          G_CALLBACK(repoman_download), &rmi);
611
612         /* Cancel button. */
613         gtk_dialog_add_button(GTK_DIALOG(rmi.dialog),
614                               GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
615
616         hbox = gtk_hbox_new(FALSE, 4);
617
618         gtk_box_pack_start(GTK_BOX(hbox),
619                            rmi.cmb_repos =
620                            gtk_combo_box_new_text(), TRUE, TRUE, 4);
621
622         gtk_box_pack_start(GTK_BOX(hbox),
623                            gtk_vseparator_new(), FALSE, FALSE, 4);
624         gtk_box_pack_start(GTK_BOX(hbox),
625                            btn_rename =
626                            gtk_button_new_with_label(_("Rename...")), FALSE,
627                            FALSE, 4);
628         gtk_box_pack_start(GTK_BOX(hbox), btn_delete =
629                            gtk_button_new_with_label(_("Delete...")), FALSE,
630                            FALSE, 4);
631         gtk_box_pack_start(GTK_BOX(hbox), btn_new =
632                            gtk_button_new_with_label(_("New...")), FALSE, FALSE,
633                            4);
634
635         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox),
636                            hbox, FALSE, FALSE, 4);
637
638         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox),
639                            gtk_hseparator_new(), TRUE, TRUE, 4);
640         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(rmi.dialog)->vbox),
641                            rmi.notebook = gtk_notebook_new(), TRUE, TRUE, 4);
642
643         gtk_notebook_set_show_tabs(GTK_NOTEBOOK(rmi.notebook), FALSE);
644         gtk_notebook_set_show_border(GTK_NOTEBOOK(rmi.notebook), FALSE);
645
646         rmi.repo_edits = NULL;
647
648         /* Populate combo box and pages in notebook. */
649         for (i = 0, curr = _repo_list; curr; curr = curr->next, i++) {
650                 RepoData *rd = (RepoData *) curr->data;
651                 RepoEditInfo *rei = repoman_dialog_add_repo(&rmi, g_strdup(rd->name));
652
653                 /* Initialize fields with data from the RepoData object. */
654                 gtk_entry_set_text(GTK_ENTRY(rei->txt_url), rd->url);
655                 gtk_entry_set_text(GTK_ENTRY(rei->txt_cache_dir), rd->cache_dir);
656                 hildon_controlbar_set_value(HILDON_CONTROLBAR
657                                             (rei->num_dl_zoom_steps),
658                                             rd->dl_zoom_steps);
659                 hildon_controlbar_set_value(HILDON_CONTROLBAR
660                                             (rei->num_view_zoom_steps),
661                                             rd->view_zoom_steps);
662                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
663                                              (rei->chk_double_size),
664                                              rd->double_size);
665                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON
666                                              (rei->chk_nextable), rd->nextable);
667                 if (rd == _curr_repo)
668                         curr_repo_index = i;
669         }
670
671         /* Connect signals. */
672         g_signal_connect(G_OBJECT(btn_rename), "clicked", G_CALLBACK(repoman_dialog_rename), &rmi);
673         g_signal_connect(G_OBJECT(btn_delete), "clicked", G_CALLBACK(repoman_dialog_delete), &rmi);
674         g_signal_connect(G_OBJECT(btn_new), "clicked", G_CALLBACK(repoman_dialog_new), &rmi);
675         g_signal_connect(G_OBJECT(rmi.cmb_repos), "changed", G_CALLBACK(repoman_dialog_select), &rmi);
676         gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), curr_repo_index);
677         gtk_notebook_set_current_page(GTK_NOTEBOOK(rmi.notebook), curr_repo_index);
678
679         gtk_widget_show_all(rmi.dialog);
680
681         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(rmi.dialog))) {
682                 /* Iterate through repos and verify each. */
683                 gboolean verified = TRUE;
684                 gint i;
685                 GList *curr;
686                 gchar *old_curr_repo_name = _curr_repo->name;
687
688                 for (i = 0, curr = rmi.repo_edits;
689                      verified && curr; curr = curr->next, i++) {
690                         RepoEditInfo *rei = curr->data;
691                         gchar *expanded = gnome_vfs_expand_initial_tilde(gtk_entry_get_text(GTK_ENTRY(rei->txt_cache_dir)));
692                         verified = repo_make_cache_dir(rei->name, expanded,     rmi.dialog);
693                         g_free(expanded);
694                 }
695                 if (!verified) {
696                         gtk_combo_box_set_active(GTK_COMBO_BOX(rmi.cmb_repos), i - 1);
697                         continue;
698                 }
699
700                 /* ** */
701
702                 /* But keep the repo list in memory, in case downloads are using it. */
703                 _repo_list = NULL;
704
705                 /* Write new _repo_list. */
706                 curr_repo_index = gtk_combo_box_get_active(GTK_COMBO_BOX(rmi.cmb_repos));
707                 _curr_repo = NULL;
708                 for (i = 0, curr = rmi.repo_edits; curr; curr = curr->next, i++) {
709                         RepoEditInfo *rei = curr->data;
710                         RepoData *rd = g_new(RepoData, 1);
711                         rd->name = g_strdup(rei->name);
712                         rd->url = g_strdup(gtk_entry_get_text(GTK_ENTRY(rei->txt_url)));
713                         rd->cache_dir = gnome_vfs_expand_initial_tilde(gtk_entry_get_text(GTK_ENTRY(rei->txt_cache_dir)));
714                         rd->dl_zoom_steps = hildon_controlbar_get_value(HILDON_CONTROLBAR(rei->num_dl_zoom_steps));
715                         rd->view_zoom_steps = hildon_controlbar_get_value(HILDON_CONTROLBAR(rei->num_view_zoom_steps));
716                         rd->double_size = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rei->chk_double_size));
717                         rd->nextable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rei->chk_nextable));
718                         set_repo_type(rd);
719
720                         _repo_list = g_list_append(_repo_list, rd);
721
722                         if (!_curr_repo && !strcmp(old_curr_repo_name, rd->name))
723                                 repo_set_curr(rd);
724                         else if (i == curr_repo_index)
725                                 repo_set_curr(rd);
726                 }
727                 if (!_curr_repo)
728                         repo_set_curr((RepoData *) g_list_first(_repo_list)->data);
729
730                 menu_maps_add_repos();
731
732                 config_save_repo();
733                 break;
734         }
735
736         gtk_widget_hide(rmi.dialog);    /* Destroying causes a crash (!?!?!??!) */
737
738         map_set_zoom(_zoom);    /* make sure we're at an appropriate zoom level. */
739
740         return TRUE;
741 }
742
743 static gboolean
744 mapman_by_area(gfloat start_lat, gfloat start_lon,
745                gfloat end_lat, gfloat end_lon, MapmanInfo * mapman_info,
746                gboolean is_deleting, gboolean is_overwriting)
747 {
748         guint start_unitx, start_unity, end_unitx, end_unity;
749         guint num_maps = 0;
750         guint i;
751         gchar buffer[80];
752         GtkWidget *confirm;
753
754         latlon2unit(start_lat, start_lon, start_unitx, start_unity);
755         latlon2unit(end_lat, end_lon, end_unitx, end_unity);
756
757         /* Swap if they specified flipped lats or lons. */
758         if (start_unitx > end_unitx) {
759                 guint swap = start_unitx;
760                 start_unitx = end_unitx;
761                 end_unitx = swap;
762         }
763         if (start_unity > end_unity) {
764                 guint swap = start_unity;
765                 start_unity = end_unity;
766                 end_unity = swap;
767         }
768
769         /* First, get the number of maps to download. */
770         for (i = 0; i < MAX_ZOOM; i++) {
771                 if (gtk_toggle_button_get_active
772                     (GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
773                         guint start_tilex, start_tiley, end_tilex, end_tiley;
774                         start_tilex = unit2ztile(start_unitx, i);
775                         start_tiley = unit2ztile(start_unity, i);
776                         end_tilex = unit2ztile(end_unitx, i);
777                         end_tiley = unit2ztile(end_unity, i);
778                         num_maps += (end_tilex - start_tilex + 1)
779                             * (end_tiley - start_tiley + 1);
780                 }
781         }
782
783         if (is_deleting) {
784                 g_snprintf(buffer, sizeof(buffer), "%s %d %s",
785                          _("Confirm DELETION of"), num_maps, _("maps "));
786         } else {
787                 g_snprintf(buffer, sizeof(buffer),
788                          "%s %d %s\n(%s %.2f MB)\n", _("Confirm download of"),
789                          num_maps, _("maps"), _("up to about"),
790                          num_maps *
791                          (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
792         }
793         confirm = hildon_note_new_confirmation(GTK_WINDOW(mapman_info->dialog), buffer);
794
795         if (GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm))) {
796                 gtk_widget_destroy(confirm);
797                 return FALSE;
798         }
799         for (i = 0; i < MAX_ZOOM; i++) {
800                 if (gtk_toggle_button_get_active
801                     (GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
802                         guint start_tilex, start_tiley, end_tilex, end_tiley;
803                         guint tilex, tiley;
804                         start_tilex = unit2ztile(start_unitx, i);
805                         start_tiley = unit2ztile(start_unity, i);
806                         end_tilex = unit2ztile(end_unitx, i);
807                         end_tiley = unit2ztile(end_unity, i);
808                         for (tiley = start_tiley; tiley <= end_tiley; tiley++)
809                                 for (tilex = start_tilex; tilex <= end_tilex;
810                                      tilex++)
811                                         map_initiate_download(tilex, tiley, i,
812                                                               is_deleting ? 0
813                                                               : (is_overwriting
814                                                                  ?
815                                                                  -INITIAL_DOWNLOAD_RETRIES
816                                                                  :
817                                                                  INITIAL_DOWNLOAD_RETRIES));
818                 }
819         }
820         gtk_widget_destroy(confirm);
821         return TRUE;
822 }
823
824 static gboolean
825 mapman_by_route(MapmanInfo * mapman_info,
826                 gboolean is_deleting, gboolean is_overwriting)
827 {
828         GtkWidget *confirm;
829         guint prev_tilex, prev_tiley, num_maps = 0, i;
830         Point *curr;
831         gchar buffer[80];
832         guint radius = hildon_number_editor_get_value(HILDON_NUMBER_EDITOR(mapman_info->num_route_radius));
833
834         /* First, get the number of maps to download. */
835         for (i = 0; i < MAX_ZOOM; i++) {
836                 if (gtk_toggle_button_get_active
837                     (GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
838                         prev_tilex = 0;
839                         prev_tiley = 0;
840                         for (curr = _route.head - 1; curr++ != _route.tail;) {
841                                 if (curr->unity) {
842                                         guint tilex =
843                                             unit2ztile(curr->unitx, i);
844                                         guint tiley =
845                                             unit2ztile(curr->unity, i);
846                                         if (tilex != prev_tilex
847                                             || tiley != prev_tiley) {
848                                                 if (prev_tiley)
849                                                         num_maps +=
850                                                             (abs
851                                                              ((gint) tilex -
852                                                               prev_tilex) + 1)
853                                                             *
854                                                             (abs
855                                                              ((gint) tiley -
856                                                               prev_tiley) + 1) -
857                                                             1;
858                                                 prev_tilex = tilex;
859                                                 prev_tiley = tiley;
860                                         }
861                                 }
862                         }
863                 }
864         }
865         num_maps *= 0.625 * pow(radius + 1, 1.85);
866
867         if (is_deleting) {
868                 g_snprintf(buffer, sizeof(buffer), "%s %s %d %s",
869                          _("Confirm DELETION of"), _("about"),
870                          num_maps, _("maps "));
871         } else {
872                 g_snprintf(buffer, sizeof(buffer),
873                          "%s %s %d %s\n(%s %.2f MB)\n",
874                          _("Confirm download of"), _("about"), num_maps,
875                          _("maps"), _("up to about"),
876                          num_maps *
877                          (strstr(_curr_repo->url, "%s") ? 18e-3 : 6e-3));
878         }
879         confirm =
880             hildon_note_new_confirmation(GTK_WINDOW(mapman_info->dialog),
881                                          buffer);
882
883         if (GTK_RESPONSE_OK != gtk_dialog_run(GTK_DIALOG(confirm))) {
884                 gtk_widget_destroy(confirm);
885                 return FALSE;
886         }
887
888         /* Now, do the actual download. */
889         for (i = 0; i < MAX_ZOOM; i++) {
890                 if (gtk_toggle_button_get_active
891                     (GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]))) {
892                         prev_tilex = 0;
893                         prev_tiley = 0;
894                         for (curr = _route.head - 1; curr++ != _route.tail;) {
895                                 if (curr->unity) {
896                                         guint tilex =
897                                             unit2ztile(curr->unitx, i);
898                                         guint tiley =
899                                             unit2ztile(curr->unity, i);
900                                         if (tilex != prev_tilex
901                                             || tiley != prev_tiley) {
902                                                 guint minx, miny, maxx, maxy, x,
903                                                     y;
904                                                 if (prev_tiley != 0) {
905                                                         minx = MIN(tilex, prev_tilex) - radius;
906                                                         miny = MIN(tiley, prev_tiley) - radius;
907                                                         maxx = MAX(tilex, prev_tilex) + radius;
908                                                         maxy = MAX(tiley, prev_tiley) + radius;
909                                                 } else {
910                                                         minx = tilex - radius;
911                                                         miny = tiley - radius;
912                                                         maxx = tilex + radius;
913                                                         maxy = tiley + radius;
914                                                 }
915                                                 for (x = minx; x <= maxx; x++)
916                                                         for (y = miny;
917                                                              y <= maxy; y++)
918                                                                 map_initiate_download
919                                                                     (x, y, i,
920                                                                      is_deleting
921                                                                      ? 0
922                                                                      :
923                                                                      (is_overwriting
924                                                                       ?
925                                                                       -INITIAL_DOWNLOAD_RETRIES
926                                                                       :
927                                                                       INITIAL_DOWNLOAD_RETRIES));
928                                                 prev_tilex = tilex;
929                                                 prev_tiley = tiley;
930                                         }
931                                 }
932                         }
933                 }
934         }
935         _route_dl_radius = radius;
936         gtk_widget_destroy(confirm);
937         return TRUE;
938 }
939
940 static void 
941 mapman_clear(GtkWidget * widget, MapmanInfo * mapman_info)
942 {
943 guint i;
944
945 if (gtk_notebook_get_current_page(GTK_NOTEBOOK(mapman_info->notebook))) {
946         /* This is the second page (the "Zoom" page) - clear the checks. */
947         for (i = 0; i < MAX_ZOOM; i++)
948                 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info->chk_zoom_levels[i]), FALSE);
949 } else {
950         /* This is the first page (the "Area" page) - clear the text fields. */
951         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lat), "");
952         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_topleft_lon), "");
953         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lat), "");
954         gtk_entry_set_text(GTK_ENTRY(mapman_info->txt_botright_lon), "");
955 }
956 }
957
958 static void 
959 mapman_update_state(GtkWidget * widget, MapmanInfo * mapman_info)
960 {
961 gtk_widget_set_sensitive(mapman_info->chk_overwrite,
962          gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info->rad_download)));
963
964         if (gtk_toggle_button_get_active
965             (GTK_TOGGLE_BUTTON(mapman_info->rad_by_area)))
966                 gtk_widget_show(mapman_info->tbl_area);
967         else if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(mapman_info->notebook))
968                  == 3)
969                 gtk_widget_hide(mapman_info->tbl_area);
970
971         gtk_widget_set_sensitive(mapman_info->num_route_radius,
972                                  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
973                                                               (mapman_info->rad_by_route)));
974 }
975
976 gboolean menu_cb_mapman(GtkAction * action)
977 {
978         GtkWidget *dialog;
979         GtkWidget *vbox;
980         GtkWidget *hbox;
981         GtkWidget *table;
982         GtkWidget *label;
983         GtkWidget *button;
984         GtkWidget *lbl_gps_lat;
985         GtkWidget *lbl_gps_lon;
986         GtkWidget *lbl_center_lat;
987         GtkWidget *lbl_center_lon;
988         MapmanInfo mapman_info;
989         gchar buffer[80];
990         gfloat lat, lon;
991         guint i;
992
993         mapman_info.dialog = dialog = gtk_dialog_new_with_buttons(_("Manage Maps"), GTK_WINDOW(_window),
994                                         GTK_DIALOG_MODAL, GTK_STOCK_OK,
995                                         GTK_RESPONSE_ACCEPT, NULL);
996
997         help_dialog_help_enable(GTK_DIALOG(mapman_info.dialog), HELP_ID_MAPMAN);
998
999         /* Clear button. */
1000         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1001                           button = gtk_button_new_with_label(_("Clear")));
1002         g_signal_connect(G_OBJECT(button), "clicked",
1003                          G_CALLBACK(mapman_clear), &mapman_info);
1004
1005         /* Cancel button. */
1006         gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
1007
1008         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1009                            mapman_info.notebook = gtk_notebook_new(), TRUE, TRUE, 0);
1010
1011         /* Setup page. */
1012         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
1013                                  vbox = gtk_vbox_new(FALSE, 2),
1014                                  label = gtk_label_new(_("Setup")));
1015         gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(mapman_info.notebook),
1016                                            vbox, FALSE, FALSE, GTK_PACK_START);
1017
1018         gtk_box_pack_start(GTK_BOX(vbox),
1019                            hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 0);
1020         gtk_box_pack_start(GTK_BOX(hbox),
1021                            mapman_info.rad_download = gtk_radio_button_new_with_label(NULL, _("Download Maps")), FALSE, FALSE, 0);
1022         gtk_box_pack_start(GTK_BOX(hbox), label =
1023                            gtk_alignment_new(0.f, 0.5f, 0.f, 0.f), FALSE, FALSE,
1024                            0);
1025         gtk_container_add(GTK_CONTAINER(label), mapman_info.chk_overwrite =
1026                           gtk_check_button_new_with_label(_("Overwrite"))),
1027             gtk_box_pack_start(GTK_BOX(vbox), mapman_info.rad_delete =
1028                                gtk_radio_button_new_with_label_from_widget
1029                                (GTK_RADIO_BUTTON(mapman_info.rad_download),
1030                                 _("Delete Maps")), FALSE, FALSE, 0);
1031
1032         gtk_box_pack_start(GTK_BOX(vbox),
1033                            gtk_hseparator_new(), FALSE, FALSE, 0);
1034
1035         gtk_box_pack_start(GTK_BOX(vbox),
1036                            mapman_info.rad_by_area
1037                            = gtk_radio_button_new_with_label(NULL, _("By Area (see tab)")), FALSE, FALSE, 0);
1038         gtk_box_pack_start(GTK_BOX(vbox), hbox =
1039                            gtk_hbox_new(FALSE, 4), FALSE, FALSE, 0);
1040         gtk_box_pack_start(GTK_BOX(hbox), mapman_info.rad_by_route =
1041                            gtk_radio_button_new_with_label_from_widget
1042                            (GTK_RADIO_BUTTON(mapman_info.rad_by_area),
1043                             _("Along Route - Radius (tiles):")), FALSE, FALSE,
1044                            0);
1045         gtk_widget_set_sensitive(mapman_info.rad_by_route,
1046                                  _route.head != _route.tail);
1047         gtk_box_pack_start(GTK_BOX(hbox), mapman_info.num_route_radius =
1048                            hildon_number_editor_new(0, 100), FALSE, FALSE, 0);
1049         hildon_number_editor_set_value(HILDON_NUMBER_EDITOR
1050                                        (mapman_info.num_route_radius),
1051                                        _route_dl_radius);
1052
1053         /* Zoom page. */
1054         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
1055                                  table = gtk_table_new(5, 5, FALSE),
1056                                  label = gtk_label_new(_("Zoom")));
1057         gtk_notebook_set_tab_label_packing(GTK_NOTEBOOK(mapman_info.notebook),
1058                                            table, FALSE, FALSE, GTK_PACK_START);
1059         gtk_table_attach(GTK_TABLE(table), label =
1060                          gtk_label_new(_
1061                                        ("Zoom Levels to Download: (0 = most detail)")),
1062                          0, 4, 0, 1, GTK_FILL, 0, 4, 0);
1063         gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
1064         for (i = 0; i < MAX_ZOOM; i++) {
1065                 g_snprintf(buffer, sizeof(buffer), "%d", i);
1066                 gtk_table_attach(GTK_TABLE(table),
1067                                  mapman_info.chk_zoom_levels[i]
1068                                  = gtk_check_button_new_with_label(buffer),
1069                                  i % 4, i % 4 + 1, i / 4 + 1, i / 4 + 2,
1070                                  GTK_EXPAND | GTK_FILL, 0, 4, 0);
1071         }
1072
1073         /* Area page. */
1074         gtk_notebook_append_page(GTK_NOTEBOOK(mapman_info.notebook),
1075                                  mapman_info.tbl_area =
1076                                  gtk_table_new(3, 4, FALSE), label =
1077                                  gtk_label_new(_("Area")));
1078
1079         /* Label Columns. */
1080         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1081                          label = gtk_label_new(_("Latitude")),
1082                          1, 2, 0, 1, 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                          label = gtk_label_new(_("Longitude")),
1086                          2, 3, 0, 1, GTK_FILL, 0, 4, 0);
1087         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1088
1089         /* GPS. */
1090         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1091                          label = gtk_label_new(_("GPS Location")),
1092                          0, 1, 1, 2, GTK_FILL, 0, 4, 0);
1093         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1094         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1095                          lbl_gps_lat = gtk_label_new(""),
1096                          1, 2, 1, 2, GTK_FILL, 0, 4, 0);
1097         gtk_label_set_selectable(GTK_LABEL(lbl_gps_lat), TRUE);
1098         gtk_misc_set_alignment(GTK_MISC(lbl_gps_lat), 1.f, 0.5f);
1099         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1100                          lbl_gps_lon = gtk_label_new(""),
1101                          2, 3, 1, 2, GTK_FILL, 0, 4, 0);
1102         gtk_label_set_selectable(GTK_LABEL(lbl_gps_lon), TRUE);
1103         gtk_misc_set_alignment(GTK_MISC(lbl_gps_lon), 1.f, 0.5f);
1104
1105         /* Center. */
1106         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1107                          label = gtk_label_new(_("View Center")),
1108                          0, 1, 2, 3, GTK_FILL, 0, 4, 0);
1109         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1110         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1111                          lbl_center_lat = gtk_label_new(""),
1112                          1, 2, 2, 3, GTK_FILL, 0, 4, 0);
1113         gtk_label_set_selectable(GTK_LABEL(lbl_center_lat), TRUE);
1114         gtk_misc_set_alignment(GTK_MISC(lbl_center_lat), 1.f, 0.5f);
1115         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1116                          lbl_center_lon = gtk_label_new(""),
1117                          2, 3, 2, 3, GTK_FILL, 0, 4, 0);
1118         gtk_label_set_selectable(GTK_LABEL(lbl_center_lon), TRUE);
1119         gtk_misc_set_alignment(GTK_MISC(lbl_center_lon), 1.f, 0.5f);
1120
1121         /* default values for Top Left and Bottom Right are defined by the
1122          * rectangle of the current and the previous Center */
1123
1124         /* Top Left. */
1125         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1126                          label = gtk_label_new(_("Top-Left")),
1127                          0, 1, 3, 4, GTK_FILL, 0, 4, 0);
1128         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1129         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1130                          mapman_info.txt_topleft_lat = gtk_entry_new(),
1131                          1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 4, 0);
1132         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lat), 1.f);
1133         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1134                          mapman_info.txt_topleft_lon = gtk_entry_new(),
1135                          2, 3, 3, 4, GTK_EXPAND | GTK_FILL, 0, 4, 0);
1136         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_topleft_lon), 1.f);
1137
1138         /* Bottom Right. */
1139         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1140                          label = gtk_label_new(_("Bottom-Right")),
1141                          0, 1, 4, 5, GTK_FILL, 0, 4, 0);
1142         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1143         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1144                          mapman_info.txt_botright_lat = gtk_entry_new(),
1145                          1, 2, 4, 5, GTK_EXPAND | GTK_FILL, 0, 4, 0);
1146         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lat), 1.f);
1147         gtk_table_attach(GTK_TABLE(mapman_info.tbl_area),
1148                          mapman_info.txt_botright_lon = gtk_entry_new(),
1149                          2, 3, 4, 5, GTK_EXPAND | GTK_FILL, 0, 4, 0);
1150         gtk_entry_set_alignment(GTK_ENTRY(mapman_info.txt_botright_lon), 1.f);
1151
1152 #if defined(WITH_DEVICE_770) && !defined(WITH_HILDON_NEW)
1153         /* Set hildon input hints */
1154         g_object_set(G_OBJECT(mapman_info.txt_topleft_lon),
1155                      HILDON_INPUT_MODE_HINT,
1156                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
1157         g_object_set(G_OBJECT(mapman_info.txt_topleft_lat),
1158                      HILDON_INPUT_MODE_HINT,
1159                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
1160         g_object_set(G_OBJECT(mapman_info.txt_botright_lon),
1161                      HILDON_INPUT_MODE_HINT,
1162                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
1163         g_object_set(G_OBJECT(mapman_info.txt_botright_lat),
1164                      HILDON_INPUT_MODE_HINT,
1165                      HILDON_INPUT_MODE_HINT_NUMERICSPECIAL, NULL);
1166 #endif
1167
1168         /* Default action is to download by area. */
1169         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info.rad_by_area), TRUE);
1170
1171         /* Initialize fields.  Do no use g_ascii_formatd; these strings will be
1172          * output (and parsed) as locale-dependent. */
1173
1174         g_snprintf(buffer, sizeof(buffer), "%.06f", _gps.lat);
1175         gtk_label_set_text(GTK_LABEL(lbl_gps_lat), buffer);
1176         g_snprintf(buffer, sizeof(buffer), "%.06f", _gps.lon);
1177         gtk_label_set_text(GTK_LABEL(lbl_gps_lon), buffer);
1178
1179         unit2latlon(_center.unitx, _center.unity, lat, lon);
1180         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1181         gtk_label_set_text(GTK_LABEL(lbl_center_lat), buffer);
1182         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1183         gtk_label_set_text(GTK_LABEL(lbl_center_lon), buffer);
1184
1185         /* Initialize to the bounds of the screen. */
1186         unit2latlon(x2unit(0), y2unit(0), lat, lon);
1187         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1188         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lat), buffer);
1189         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1190         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_topleft_lon), buffer);
1191
1192         unit2latlon(x2unit(_screen_width_pixels), y2unit(_screen_height_pixels), lat, lon);
1193         g_snprintf(buffer, sizeof(buffer), "%.06f", lat);
1194         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lat), buffer);
1195         g_snprintf(buffer, sizeof(buffer), "%.06f", lon);
1196         gtk_entry_set_text(GTK_ENTRY(mapman_info.txt_botright_lon), buffer);
1197
1198         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mapman_info.chk_zoom_levels[_zoom]), TRUE);
1199
1200         gtk_widget_show_all(dialog);
1201
1202         mapman_update_state(NULL, &mapman_info);
1203
1204         /* Connect signals. */
1205         if (_curr_repo->type != REPOTYPE_NONE) {
1206                 g_signal_connect(G_OBJECT(mapman_info.rad_download), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1207                 gtk_widget_set_sensitive(mapman_info.rad_download, TRUE);
1208         } else {
1209                 gtk_widget_set_sensitive(mapman_info.rad_download, FALSE);
1210                 popup_error(dialog, _("NOTE: You must set a Map URI in the current repository in order to download maps."));
1211         }
1212
1213         g_signal_connect(G_OBJECT(mapman_info.rad_delete), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1214         g_signal_connect(G_OBJECT(mapman_info.rad_by_area), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1215         g_signal_connect(G_OBJECT(mapman_info.rad_by_route), "clicked", G_CALLBACK(mapman_update_state), &mapman_info);
1216
1217         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
1218                 gboolean is_deleting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.rad_delete));
1219                 gboolean is_overwriting = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.chk_overwrite));
1220                 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(mapman_info.rad_by_route))) {
1221                         if (mapman_by_route(&mapman_info, is_deleting, is_overwriting))
1222                                 break;
1223                 } else {
1224                         const gchar *text;
1225                         gchar *error_check;
1226                         gfloat start_lat, start_lon, end_lat, end_lon;
1227
1228                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lat));
1229                         start_lat = strtof(text, &error_check);
1230                         if (text == error_check || start_lat < -90.f || start_lat > 90.f) {
1231                                 popup_error(dialog, _("Invalid Top-Left Latitude"));
1232                                 continue;
1233                         }
1234
1235                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_topleft_lon));
1236                         start_lon = strtof(text, &error_check);
1237                         if (text == error_check || start_lon < -180.f || start_lon > 180.f) {
1238                                 popup_error(dialog, _("Invalid Top-Left Longitude"));
1239                                 continue;
1240                         }
1241
1242                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lat));
1243                         end_lat = strtof(text, &error_check);
1244                         if (text == error_check || end_lat < -90.f || end_lat > 90.f) {
1245                                 popup_error(dialog, _("Invalid Bottom-Right Latitude"));
1246                                 continue;
1247                         }
1248
1249                         text = gtk_entry_get_text(GTK_ENTRY(mapman_info.txt_botright_lon));
1250                         end_lon = strtof(text, &error_check);
1251                         if (text == error_check || end_lon < -180.f || end_lon > 180.f) {
1252                                 popup_error(dialog, _("Invalid Bottom-Right Longitude"));
1253                                 continue;
1254                         }
1255
1256                         if (mapman_by_area(start_lat, start_lon, end_lat, end_lon, &mapman_info, is_deleting, is_overwriting))
1257                                 break;
1258                 }
1259         }
1260
1261         gtk_widget_hide(dialog);        /* Destroying causes a crash (!?!?!??!) */
1262
1263         return TRUE;
1264 }