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