]> err.no Git - mapper/blob - src/poi-gui.c
f67ab5394518a95ad68d995159a3eb877b0152e5
[mapper] / src / poi-gui.c
1 #include <config.h>
2
3 #define _GNU_SOURCE
4
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <strings.h>
9 #include <stddef.h>
10 #include <locale.h>
11 #include <math.h>
12 #include <errno.h>
13 #include <sys/wait.h>
14 #include <glib/gstdio.h>
15 #include <gtk/gtk.h>
16 #include <fcntl.h>
17 #include <libgnomevfs/gnome-vfs.h>
18 #include <curl/multi.h>
19 #include <gconf/gconf-client.h>
20 #include <libxml/parser.h>
21
22 #include <libintl.h>
23 #include <locale.h>
24
25 #include <sqlite3.h>
26
27 #include "utils.h"
28 #include "poi.h"
29 #include "gps.h"
30 #include "map.h"
31 #include "mapper-types.h"
32 #include "ui-common.h"
33 #include "settings.h"
34
35 guint _poi_zoom = 6;
36
37 gboolean category_delete(GtkWidget * widget, DeletePOI * dpoi)
38 {
39         GtkWidget *dialog;
40         guint i;
41         gchar *buffer;
42         printf("%s()\n", __PRETTY_FUNCTION__);
43
44         buffer = g_strdup_printf("%s\n\t%s\n%s",
45                                  _("Delete category?"),
46                                  dpoi->txt_label,
47                                  _("WARNING: All POIs in that category will also be deleted!"));
48         dialog = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
49         g_free(buffer);
50         i = gtk_dialog_run(GTK_DIALOG(dialog));
51         gtk_widget_destroy(GTK_WIDGET(dialog));
52
53         if (i == GTK_RESPONSE_OK) {
54                 /* delete dpoi->poi_id */
55                 if (SQLITE_OK != sqlite3_bind_int(_stmt_delete_poi_by_catid, 1, dpoi->id) ||
56                     SQLITE_DONE != sqlite3_step(_stmt_delete_poi_by_catid)) {
57                         MACRO_BANNER_SHOW_INFO(_window, _("Problem deleting POI"));
58                         sqlite3_reset(_stmt_delete_poi_by_catid);
59                         return FALSE;
60                 }
61                 sqlite3_reset(_stmt_delete_poi_by_catid);
62
63                 if (SQLITE_OK != sqlite3_bind_int(_stmt_delete_cat, 1, dpoi->id)
64                     || SQLITE_DONE != sqlite3_step(_stmt_delete_cat)) {
65                         MACRO_BANNER_SHOW_INFO(_window, _("Problem deleting category"));
66                         sqlite3_reset(_stmt_delete_cat);
67                         return FALSE;
68                 }
69                 sqlite3_reset(_stmt_delete_cat);
70
71                 gtk_widget_hide_all(dpoi->dialog);
72                 map_force_redraw();
73         }
74
75         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
76         return TRUE;
77 }
78
79 gboolean category_dialog(guint cat_id)
80 {
81         gchar *cat_label = NULL, *cat_desc = NULL;
82         guint cat_enabled;
83         GtkWidget *dialog;
84         GtkWidget *table;
85         GtkWidget *label;
86         GtkWidget *txt_label;
87         GtkWidget *txt_desc;
88         GtkWidget *btn_delete = NULL;
89         GtkWidget *txt_scroll;
90         GtkWidget *chk_enabled;
91         GtkTextBuffer *desc_txt;
92         GtkTextIter begin, end;
93         gboolean results = TRUE;
94         DeletePOI dpoi = { NULL, NULL, 0 };
95         printf("%s()\n", __PRETTY_FUNCTION__);
96
97         if (cat_id > 0) {
98                 if (SQLITE_OK !=
99                     sqlite3_bind_double(_stmt_select_cat, 1, cat_id)
100                     || SQLITE_ROW != sqlite3_step(_stmt_select_cat)) {
101                         vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
102                         sqlite3_reset(_stmt_select_cat);
103                         return FALSE;
104                 }
105
106                 cat_label = g_strdup(sqlite3_column_text(_stmt_select_cat, 0));
107                 cat_desc = g_strdup(sqlite3_column_text(_stmt_select_cat, 1));
108                 cat_enabled = sqlite3_column_int(_stmt_select_cat, 2);
109
110                 sqlite3_reset(_stmt_select_cat);
111
112                 dialog = gtk_dialog_new_with_buttons(_("Edit Category"),
113                                                      GTK_WINDOW(_window),
114                                                      GTK_DIALOG_MODAL,
115                                                      GTK_STOCK_OK,
116                                                      GTK_RESPONSE_ACCEPT, NULL);
117
118                 gtk_container_add(GTK_CONTAINER
119                                   (GTK_DIALOG(dialog)->action_area),
120                                   btn_delete =
121                                   gtk_button_new_with_label(_("Delete")));
122
123                 dpoi.dialog = dialog;
124                 dpoi.txt_label = g_strdup(cat_label);
125                 dpoi.id = cat_id;
126
127                 g_signal_connect(G_OBJECT(btn_delete), "clicked",
128                                  G_CALLBACK(category_delete), &dpoi);
129
130                 gtk_dialog_add_button(GTK_DIALOG(dialog),
131                                       GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
132         } else {
133                 cat_enabled = 1;
134                 cat_label = g_strdup("");
135                 cat_id = 0;
136                 cat_desc = g_strdup("");
137
138                 dialog = gtk_dialog_new_with_buttons(_("Add Category"),
139                                                      GTK_WINDOW(_window),
140                                                      GTK_DIALOG_MODAL,
141                                                      GTK_STOCK_OK,
142                                                      GTK_RESPONSE_ACCEPT,
143                                                      GTK_STOCK_CANCEL,
144                                                      GTK_RESPONSE_REJECT, NULL);
145         }
146
147         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
148                            table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
149
150         gtk_table_attach(GTK_TABLE(table),
151                          label = gtk_label_new(_("Label")),
152                          0, 1, 0, 1, GTK_FILL, 0, 2, 4);
153         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
154         gtk_table_attach(GTK_TABLE(table),
155                          txt_label = gtk_entry_new(),
156                          1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
157
158         gtk_table_attach(GTK_TABLE(table),
159                          label = gtk_label_new(_("Description")),
160                          0, 1, 1, 2, GTK_FILL, 0, 2, 4);
161         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
162
163         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
164         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
165                                             GTK_SHADOW_IN);
166         gtk_table_attach(GTK_TABLE(table),
167                          txt_scroll,
168                          1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
169
170         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
171                                        GTK_POLICY_AUTOMATIC,
172                                        GTK_POLICY_AUTOMATIC);
173
174         txt_desc = gtk_text_view_new();
175         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
176
177         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
178         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
179
180         desc_txt = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
181
182         gtk_table_attach(GTK_TABLE(table),
183                          chk_enabled =
184                          gtk_check_button_new_with_label(_("Enabled")), 0, 2, 2,
185                          3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
186
187         /* label */
188         gtk_entry_set_text(GTK_ENTRY(txt_label), cat_label);
189
190         /* desc */
191         gtk_text_buffer_set_text(desc_txt, cat_desc, -1);
192
193         /* enabled */
194         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enabled),
195                                      (cat_enabled == 1 ? TRUE : FALSE));
196
197         g_free(cat_label);
198         cat_label = NULL;
199         g_free(cat_desc);
200         cat_desc = NULL;
201
202         gtk_widget_show_all(dialog);
203
204         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
205                 if (strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
206                         cat_label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
207                 else {
208                         popup_error(dialog,
209                                     _("Please specify a name for the category."));
210                         continue;
211                 }
212
213                 gtk_text_buffer_get_iter_at_offset(desc_txt, &begin, 0);
214                 gtk_text_buffer_get_end_iter(desc_txt, &end);
215                 cat_desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
216
217                 cat_enabled = (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(chk_enabled)) ? 1 : 0);
218
219                 if (cat_id > 0) {
220                         /* edit category */
221                         if (SQLITE_OK !=
222                             sqlite3_bind_text(_stmt_update_cat, 1, cat_label,
223                                               -1, g_free)
224                             || SQLITE_OK != sqlite3_bind_text(_stmt_update_cat,
225                                                               2, cat_desc, -1,
226                                                               g_free)
227                             || SQLITE_OK != sqlite3_bind_int(_stmt_update_cat,
228                                                              3, cat_enabled)
229                             || SQLITE_OK != sqlite3_bind_int(_stmt_update_cat,
230                                                              4, cat_id)
231                             || SQLITE_DONE != sqlite3_step(_stmt_update_cat)) {
232                                 MACRO_BANNER_SHOW_INFO(_window,
233                                                        _("Problem updating category"));
234                                 results = FALSE;
235                         }
236                         sqlite3_reset(_stmt_update_cat);
237                 } else {
238                         /* add category */
239                         if (SQLITE_OK !=
240                             sqlite3_bind_text(_stmt_insert_cat, 1, cat_label,
241                                               -1, g_free)
242                             || SQLITE_OK != sqlite3_bind_text(_stmt_insert_cat,
243                                                               2, cat_desc, -1,
244                                                               g_free)
245                             || SQLITE_OK != sqlite3_bind_int(_stmt_insert_cat,
246                                                              3, cat_enabled)
247                             || SQLITE_DONE != sqlite3_step(_stmt_insert_cat)) {
248                                 MACRO_BANNER_SHOW_INFO(_window,
249                                                        _("Problem adding category"));
250                                 results = FALSE;
251                         }
252                         sqlite3_reset(_stmt_insert_cat);
253                 }
254                 break;
255         }
256
257         g_free(dpoi.txt_label);
258
259         g_object_unref(desc_txt);
260
261         gtk_widget_hide_all(dialog);
262
263         vprintf("%s(): return\n", __PRETTY_FUNCTION__);
264         return results;
265 }
266
267 void category_toggled(GtkCellRendererToggle * cell, gchar * path, gpointer data)
268 {
269         GtkTreeIter iter;
270         gboolean cat_enabled;
271         guint cat_id;
272         printf("%s()\n", __PRETTY_FUNCTION__);
273
274         GtkTreeModel *model = GTK_TREE_MODEL(data);
275         if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
276                 return;
277
278         gtk_tree_model_get(model, &iter, CAT_ENABLED, &cat_enabled, -1);
279         gtk_tree_model_get(model, &iter, CAT_ID, &cat_id, -1);
280
281         cat_enabled ^= 1;
282
283         if (SQLITE_OK != sqlite3_bind_int(_stmt_toggle_cat, 1, cat_enabled) ||
284             SQLITE_OK != sqlite3_bind_int(_stmt_toggle_cat, 2, cat_id) ||
285             SQLITE_DONE != sqlite3_step(_stmt_toggle_cat)) {
286                 MACRO_BANNER_SHOW_INFO(_window, _("Problem updating Category"));
287         } else
288                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
289                                    CAT_ENABLED, cat_enabled, -1);
290
291         sqlite3_reset(_stmt_toggle_cat);
292
293         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
294 }
295
296 GtkListStore *generate_store()
297 {
298         GtkTreeIter iter;
299         GtkListStore *store;
300         printf("%s()\n", __PRETTY_FUNCTION__);
301
302         store = gtk_list_store_new(CAT_NUM_COLUMNS,
303                                    G_TYPE_UINT,
304                                    G_TYPE_BOOLEAN,
305                                    G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT);
306
307         while (SQLITE_ROW == sqlite3_step(_stmt_selall_cat)) {
308                 gtk_list_store_append(store, &iter);
309                 gtk_list_store_set(store, &iter,
310                                    CAT_ID, sqlite3_column_int(_stmt_selall_cat,
311                                                               0), CAT_ENABLED,
312                                    sqlite3_column_int(_stmt_selall_cat, 3),
313                                    CAT_LABEL,
314                                    sqlite3_column_text(_stmt_selall_cat, 1),
315                                    CAT_DESC,
316                                    sqlite3_column_text(_stmt_selall_cat, 2),
317                                    CAT_POI_CNT,
318                                    sqlite3_column_int(_stmt_selall_cat, 4), -1);
319         }
320         sqlite3_reset(_stmt_selall_cat);
321
322         vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, store);
323         return store;
324 }
325
326 gboolean category_add(GtkWidget * widget, GtkWidget * tree_view)
327 {
328         GtkListStore *store;
329         printf("%s()\n", __PRETTY_FUNCTION__);
330
331         if (category_dialog(0)) {
332                 store = generate_store();
333                 gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view),
334                                         GTK_TREE_MODEL(store));
335                 g_object_unref(G_OBJECT(store));
336         }
337         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
338         return TRUE;
339 }
340
341 gboolean category_edit(GtkWidget * widget, GtkWidget * tree_view)
342 {
343         GtkTreeIter iter;
344         GtkTreeModel *store;
345         GtkTreeSelection *selection;
346         printf("%s()\n", __PRETTY_FUNCTION__);
347
348         store = gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view));
349         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
350         if (gtk_tree_selection_get_selected(selection, &store, &iter)) {
351                 GValue val;
352                 memset(&val, 0, sizeof(val));
353                 gtk_tree_model_get_value(store, &iter, 0, &val);
354                 if (category_dialog(g_value_get_uint(&val))) {
355                         GtkListStore *new_store = generate_store();
356                         gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view),
357                                                 GTK_TREE_MODEL(new_store));
358                         g_object_unref(G_OBJECT(new_store));
359                 }
360         }
361         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
362         return TRUE;
363 }
364
365 gboolean category_list()
366 {
367         GtkWidget *dialog;
368         GtkWidget *tree_view;
369         GtkWidget *sw;
370         GtkWidget *btn_edit;
371         GtkWidget *btn_add;
372         GtkTreeViewColumn *column;
373         GtkCellRenderer *renderer;
374         GtkListStore *store;
375         printf("%s()\n", __PRETTY_FUNCTION__);
376
377         dialog = gtk_dialog_new_with_buttons(_("POI Categories"),
378                                              GTK_WINDOW(_window),
379                                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
380                                              GTK_RESPONSE_ACCEPT, NULL);
381
382 #ifdef WITH_HILDON
383         /* Enable the help button. */
384         ossohelp_dialog_help_enable(GTK_DIALOG(dialog), HELP_ID_POICAT, _osso);
385 #endif
386
387         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
388                           btn_edit = gtk_button_new_with_label(_("Edit")));
389
390         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
391                           btn_add = gtk_button_new_with_label(_("Add")));
392
393         store = generate_store();
394
395         if (!store)
396                 return TRUE;
397
398         sw = gtk_scrolled_window_new(NULL, NULL);
399         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
400                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
401         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
402                            sw, TRUE, TRUE, 0);
403
404         tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
405         /* Maemo-related? */
406         g_object_set(tree_view, "allow-checkbox-mode", FALSE, NULL);
407         gtk_container_add(GTK_CONTAINER(sw), tree_view);
408
409         gtk_tree_selection_set_mode(gtk_tree_view_get_selection
410                                     (GTK_TREE_VIEW(tree_view)),
411                                     GTK_SELECTION_SINGLE);
412         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), TRUE);
413
414         renderer = gtk_cell_renderer_text_new();
415         column =
416             gtk_tree_view_column_new_with_attributes(_("ID"), renderer, "text",
417                                                      CAT_ID, NULL);
418         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
419         gtk_tree_view_column_set_max_width(column, 1);
420
421         renderer = gtk_cell_renderer_toggle_new();
422         g_signal_connect(renderer, "toggled",
423                          G_CALLBACK(category_toggled), store);
424         column =
425             gtk_tree_view_column_new_with_attributes(_("Enabled"), renderer,
426                                                      "active", CAT_ENABLED,
427                                                      NULL);
428         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
429
430         g_object_unref(G_OBJECT(store));
431
432         renderer = gtk_cell_renderer_text_new();
433         column =
434             gtk_tree_view_column_new_with_attributes(_("Label"), renderer,
435                                                      "text", CAT_LABEL, NULL);
436         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
437
438         renderer = gtk_cell_renderer_text_new();
439         column =
440             gtk_tree_view_column_new_with_attributes(_("Description"), renderer,
441                                                      "text", CAT_DESC, NULL);
442         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
443
444         renderer = gtk_cell_renderer_text_new();
445         column =
446             gtk_tree_view_column_new_with_attributes(_("# POIs"), renderer,
447                                                      "text", CAT_POI_CNT, NULL);
448         gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
449
450         gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
451         gtk_widget_show_all(dialog);
452
453         g_signal_connect(G_OBJECT(btn_edit), "clicked",
454                          G_CALLBACK(category_edit), tree_view);
455
456         g_signal_connect(G_OBJECT(btn_add), "clicked",
457                          G_CALLBACK(category_add), tree_view);
458
459         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
460                 break;
461         }
462         gtk_widget_destroy(dialog);
463
464         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
465         return TRUE;
466 }
467
468 gboolean menu_cb_category(GtkAction * action)
469 {
470         printf("%s()\n", __PRETTY_FUNCTION__);
471
472         if (category_list())
473                 map_force_redraw();
474
475         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
476         return TRUE;
477 }
478
479 gboolean poi_delete_confirm(GtkWidget * widget, DeletePOI * dpoi)
480 {
481         GtkWidget *dialog;
482         guint i;
483         gchar *buffer;
484         printf("%s()\n", __PRETTY_FUNCTION__);
485
486         buffer = g_strdup_printf("%s\n%s", _("Delete POI?"), dpoi->txt_label);
487         dialog = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
488         g_free(buffer);
489         i = gtk_dialog_run(GTK_DIALOG(dialog));
490         gtk_widget_destroy(GTK_WIDGET(dialog));
491
492         if (i == GTK_RESPONSE_OK) {
493                 if (poi_delete(dpoi)==FALSE) {
494                         MACRO_BANNER_SHOW_INFO(_window, _("Problem deleting POI"));
495                 } else {
496                         gtk_widget_hide_all(dpoi->dialog);
497                         map_force_redraw();
498                 }
499         }
500
501         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
502         return TRUE;
503 }
504
505 gboolean select_poi(guint unitx, guint unity, PoiInfo * poi)
506 {
507         guint x, y;
508         gfloat lat1, lon1, lat2, lon2;
509         GtkWidget *dialog;
510         GtkWidget *list;
511         GtkWidget *sw;
512         GtkTreeViewColumn *column;
513         GtkCellRenderer *renderer;
514         GtkListStore *store;
515         GtkTreeIter iter;
516         gboolean selected = FALSE;
517         gchar tmp1[16], tmp2[16];
518         guint num_cats = 0;
519         printf("%s()\n", __PRETTY_FUNCTION__);
520
521         x = unitx - pixel2unit(3 * _draw_width);
522         y = unity + pixel2unit(3 * _draw_width);
523         unit2latlon(x, y, lat1, lon1);
524
525         x = unitx + pixel2unit(3 * _draw_width);
526         y = unity - pixel2unit(3 * _draw_width);
527         unit2latlon(x, y, lat2, lon2);
528
529         store = gtk_list_store_new(POI_NUM_COLUMNS, G_TYPE_INT, /* POI ID */
530                                    G_TYPE_INT,  /* Category ID */
531                                    G_TYPE_FLOAT,        /* Latitude */
532                                    G_TYPE_FLOAT,        /* Longitude */
533                                    G_TYPE_STRING,       /* Lat/Lon */
534                                    G_TYPE_STRING,       /* POI Label */
535                                    G_TYPE_STRING,       /* POI Desc. */
536                                    G_TYPE_STRING);      /* Category Label */
537
538         if (SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 1, lat1) ||
539             SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 2, lat2) ||
540             SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 3, lon1) ||
541             SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 4, lon2)) {
542                 g_printerr("Failed to bind values for _stmt_select_poi");
543                 return FALSE;
544         }
545
546         while (SQLITE_ROW == sqlite3_step(_stmt_select_poi)) {
547                 gfloat lat, lon;
548                 lat = sqlite3_column_double(_stmt_select_poi, 0);
549                 lon = sqlite3_column_double(_stmt_select_poi, 1);
550                 printf("Found POI: %f, %f, %s, %s, %s\n",
551                        lat,
552                        lon,
553                        sqlite3_column_text(_stmt_select_poi, 3),
554                        sqlite3_column_text(_stmt_select_poi, 4),
555                        sqlite3_column_text(_stmt_select_poi, 6));
556                 lat_format(lat, tmp1);
557                 lon_format(lon, tmp2);
558                 gtk_list_store_append(store, &iter);
559                 gtk_list_store_set(store, &iter,
560                                    POI_POIID,
561                                    sqlite3_column_int(_stmt_select_poi, 2),
562                                    POI_CATID,
563                                    sqlite3_column_int(_stmt_select_poi, 5),
564                                    POI_LAT, lat, POI_LON, lon, POI_LATLON,
565                                    g_strdup_printf("%s, %s", tmp1, tmp2),
566                                    POI_LABEL,
567                                    sqlite3_column_text(_stmt_select_poi, 3),
568                                    POI_DESC,
569                                    sqlite3_column_text(_stmt_select_poi, 4),
570                                    POI_CATLAB,
571                                    sqlite3_column_text(_stmt_select_poi, 6),
572                                    -1);
573                 num_cats++;
574         }
575         sqlite3_reset(_stmt_select_poi);
576
577         switch (num_cats) {
578         case 0:
579                 g_object_unref(G_OBJECT(store));
580                 MACRO_BANNER_SHOW_INFO(_window, _("No POIs found."));
581                 return FALSE;
582                 break;
583         case 1:
584                 /* iter is still set to the most-recently added POI. */
585                 gtk_tree_model_get(GTK_TREE_MODEL(store),
586                                    &iter,
587                                    POI_POIID, &(poi->poi_id),
588                                    POI_CATID, &(poi->cat_id),
589                                    POI_LAT, &(poi->lat),
590                                    POI_LON, &(poi->lon),
591                                    POI_LABEL, &(poi->label),
592                                    POI_DESC, &(poi->desc), -1);
593                 g_object_unref(G_OBJECT(store));
594                 return TRUE;
595                 break;
596         }
597
598         /* There are at least 2 matching POI's - let the user select one. */
599         dialog = gtk_dialog_new_with_buttons(_("Select POI"),
600                                              GTK_WINDOW(_window),
601                                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
602                                              GTK_RESPONSE_ACCEPT,
603                                              GTK_STOCK_CANCEL,
604                                              GTK_RESPONSE_REJECT, NULL);
605
606         gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
607
608         sw = gtk_scrolled_window_new(NULL, NULL);
609         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw),
610                                             GTK_SHADOW_ETCHED_IN);
611         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
612                                        GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
613         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
614                            sw, TRUE, TRUE, 0);
615
616         list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
617         g_object_unref(G_OBJECT(store));
618         gtk_container_add(GTK_CONTAINER(sw), list);
619
620         gtk_tree_selection_set_mode(gtk_tree_view_get_selection
621                                     (GTK_TREE_VIEW(list)),
622                                     GTK_SELECTION_SINGLE);
623         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
624
625         renderer = gtk_cell_renderer_text_new();
626         column =
627             gtk_tree_view_column_new_with_attributes(_("Location"), renderer,
628                                                      "text", POI_LATLON, NULL);
629         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
630
631         renderer = gtk_cell_renderer_text_new();
632         column =
633             gtk_tree_view_column_new_with_attributes(_("Label"), renderer,
634                                                      "text", POI_LABEL, NULL);
635         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
636
637         renderer = gtk_cell_renderer_text_new();
638         column =
639             gtk_tree_view_column_new_with_attributes(_("Category"), renderer,
640                                                      "text", POI_CATLAB, NULL);
641         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
642
643         gtk_widget_show_all(dialog);
644
645         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
646                 if (gtk_tree_selection_get_selected
647                     (gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL,
648                      &iter)) {
649                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
650                                            POI_POIID, &(poi->poi_id), -1);
651                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
652                                            POI_CATID, &(poi->cat_id), -1);
653                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
654                                            POI_LATLON, &(poi->lat), -1);
655                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
656                                            POI_LATLON, &(poi->lon), -1);
657                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
658                                            POI_LABEL, &(poi->label), -1);
659                         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
660                                            POI_DESC, &(poi->desc), -1);
661                         selected = TRUE;
662                         break;
663                 } else
664                         popup_error(dialog, _("Select one POI from the list."));
665         }
666
667         gtk_widget_destroy(dialog);
668
669         vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
670         return selected;
671 }
672
673 void poi_populate_cat_combo(GtkWidget * cmb_category, guint cat_id)
674 {
675         GtkTreeIter active;
676         GtkListStore *store;
677         gboolean has_active = FALSE;
678         printf("%s()\n", __PRETTY_FUNCTION__);
679
680         store =
681             GTK_LIST_STORE(gtk_combo_box_get_model
682                            (GTK_COMBO_BOX(cmb_category)));
683         gtk_list_store_clear(store);
684
685         while (SQLITE_ROW == sqlite3_step(_stmt_selall_cat)) {
686                 GtkTreeIter iter;
687                 guint cid = sqlite3_column_int(_stmt_selall_cat, 0);
688                 gtk_list_store_append(store, &iter);
689                 gtk_list_store_set(store, &iter,
690                                    0, cid,
691                                    1, sqlite3_column_text(_stmt_selall_cat, 1),
692                                    -1);
693                 if (cid == cat_id) {
694                         active = iter;
695                         has_active = TRUE;
696                 }
697         }
698         sqlite3_reset(_stmt_selall_cat);
699
700         if (!has_active)
701                 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &active);
702
703         gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &active);
704
705         vprintf("%s(): return\n", __PRETTY_FUNCTION__);
706 }
707
708 typedef struct _PoiCategoryEditInfo PoiCategoryEditInfo;
709 struct _PoiCategoryEditInfo {
710         GtkWidget *cmb_category;
711         guint cat_id;
712 };
713
714 gboolean poi_edit_cat(GtkWidget * widget, PoiCategoryEditInfo * data)
715 {
716         printf("%s()\n", __PRETTY_FUNCTION__);
717         if (category_list())
718                 poi_populate_cat_combo(data->cmb_category, data->cat_id);
719         vprintf("%s(): return\n", __PRETTY_FUNCTION__);
720         return TRUE;
721 }
722
723 gboolean poi_dialog(POIAction action, guint unitx, guint unity)
724 {
725         PoiInfo poi;
726         gchar slat1[10], slon1[10];
727         gchar *p_latlon;
728         GtkWidget *dialog;
729         GtkWidget *table;
730         GtkWidget *label;
731         GtkWidget *txt_label;
732         GtkWidget *cmb_category;
733         GtkWidget *txt_desc;
734         GtkWidget *btn_delete = NULL;
735         GtkWidget *btn_catedit;
736         GtkWidget *hbox;
737         GtkWidget *txt_scroll;
738         GtkTextBuffer *desc_txt;
739         GtkTextIter begin, end;
740         DeletePOI dpoi = { NULL, NULL, 0 };
741         PoiCategoryEditInfo pcedit;
742         printf("%s()\n", __PRETTY_FUNCTION__);
743
744         if (action == ACTION_EDIT_POI) {
745                 if (!select_poi(unitx, unity, &poi)) {
746                         return FALSE;
747                 }
748
749                 dialog = gtk_dialog_new_with_buttons(_("Edit POI"),
750                                                      GTK_WINDOW(_window),
751                                                      GTK_DIALOG_MODAL,
752                                                      GTK_STOCK_OK,
753                                                      GTK_RESPONSE_ACCEPT, NULL);
754
755                 gtk_container_add(GTK_CONTAINER
756                                   (GTK_DIALOG(dialog)->action_area),
757                                   btn_delete =
758                                   gtk_button_new_with_label(_("Delete")));
759
760                 dpoi.dialog = dialog;
761                 dpoi.txt_label = g_strdup(poi.label);
762                 dpoi.id = poi.poi_id;
763
764                 g_signal_connect(G_OBJECT(btn_delete), "clicked",
765                                  G_CALLBACK(poi_delete_confirm), &dpoi);
766
767                 gtk_dialog_add_button(GTK_DIALOG(dialog),
768                                       GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
769         } else {
770                 if (SQLITE_ROW == sqlite3_step(_stmt_nextlabel_poi))
771                         poi.label = g_strdup_printf("Point%06d",
772                                                     sqlite3_column_int
773                                                     (_stmt_nextlabel_poi, 0));
774                 sqlite3_reset(_stmt_nextlabel_poi);
775
776                 unit2latlon(unitx, unity, poi.lat, poi.lon);
777
778                 poi.poi_id = 0;
779                 poi.cat_id = 0;
780                 poi.desc = g_strdup("");
781
782                 dialog = gtk_dialog_new_with_buttons(_("Add POI"),
783                                                      GTK_WINDOW(_window),
784                                                      GTK_DIALOG_MODAL,
785                                                      GTK_STOCK_OK,
786                                                      GTK_RESPONSE_ACCEPT,
787                                                      GTK_STOCK_CANCEL,
788                                                      GTK_RESPONSE_REJECT, NULL);
789         }
790
791         /* Set the p_latlon string. */
792         {
793                 gchar tmp1[16], tmp2[16];
794                 lat_format(poi.lat, tmp1);
795                 lon_format(poi.lon, tmp2);
796                 p_latlon = g_strdup_printf("%s, %s", tmp1, tmp2);
797         }
798
799         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
800                            table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
801
802         gtk_table_attach(GTK_TABLE(table),
803                          label = gtk_label_new(_("Lat, Lon")),
804                          0, 1, 0, 1, GTK_FILL, 0, 2, 4);
805         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
806
807         gtk_table_attach(GTK_TABLE(table),
808                          label = gtk_label_new(p_latlon),
809                          1, 3, 0, 1, GTK_FILL, 0, 2, 4);
810         gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
811
812         gtk_table_attach(GTK_TABLE(table),
813                          label = gtk_label_new(_("Label")),
814                          0, 1, 1, 2, GTK_FILL, 0, 2, 4);
815         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
816         gtk_table_attach(GTK_TABLE(table),
817                          txt_label = gtk_entry_new(),
818                          1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
819
820         gtk_table_attach(GTK_TABLE(table),
821                          label = gtk_label_new(_("Category")),
822                          0, 1, 3, 4, GTK_FILL, 0, 2, 4);
823         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
824         gtk_table_attach(GTK_TABLE(table),
825                          hbox = gtk_hbox_new(FALSE, 4),
826                          1, 2, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
827         gtk_box_pack_start(GTK_BOX(hbox), cmb_category = gtk_combo_box_new_with_model(GTK_TREE_MODEL(gtk_list_store_new(2, G_TYPE_INT,  /* Category ID */
828                                                                                                                         G_TYPE_STRING))),       /* Category Label */
829                            FALSE, FALSE, 4);
830         /* Set up the view for the combo box. */
831         {
832                 GtkCellRenderer *renderer;
833                 renderer = gtk_cell_renderer_text_new();
834                 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cmb_category),
835                                            renderer, TRUE);
836                 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cmb_category),
837                                                renderer, "text", 1, NULL);
838         }
839
840         gtk_box_pack_start(GTK_BOX(hbox),
841                            btn_catedit =
842                            gtk_button_new_with_label(_("Edit Categories...")),
843                            FALSE, FALSE, 4);
844
845         gtk_table_attach(GTK_TABLE(table),
846                          label = gtk_label_new(_("Description")),
847                          0, 1, 5, 6, GTK_FILL, 0, 2, 4);
848         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
849
850         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
851         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
852                                             GTK_SHADOW_IN);
853         gtk_table_attach(GTK_TABLE(table),
854                          txt_scroll,
855                          1, 2, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 4);
856
857         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
858                                        GTK_POLICY_AUTOMATIC,
859                                        GTK_POLICY_AUTOMATIC);
860
861         txt_desc = gtk_text_view_new();
862         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
863
864         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
865         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
866
867         desc_txt = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
868
869         /* label */
870         gtk_entry_set_text(GTK_ENTRY(txt_label), poi.label);
871
872         /* category */
873         poi_populate_cat_combo(cmb_category, poi.cat_id);
874
875         /* poi_desc */
876         gtk_text_buffer_set_text(desc_txt, poi.desc, -1);
877
878         /* Connect Signals */
879         pcedit.cmb_category = cmb_category;
880         pcedit.cat_id = poi.cat_id;
881         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
882                          G_CALLBACK(poi_edit_cat), &pcedit);
883         gtk_widget_show_all(dialog);
884
885         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
886                 const gchar *poi_label = NULL;
887                 gchar *poi_desc = NULL;
888                 GtkTreeIter iter;
889
890                 if (strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
891                         poi_label = gtk_entry_get_text(GTK_ENTRY(txt_label));
892                 else {
893                         popup_error(dialog,
894                                     _("Please specify a name for the POI."));
895                         continue;
896                 }
897
898                 if (!gtk_combo_box_get_active_iter
899                     (GTK_COMBO_BOX(cmb_category), &iter)) {
900                         popup_error(dialog,
901                                     _
902                                     ("Please specify a category for the POI."));
903                         continue;
904                 }
905
906                 gtk_text_buffer_get_iter_at_offset(desc_txt, &begin, 0);
907                 gtk_text_buffer_get_end_iter(desc_txt, &end);
908                 poi_desc =
909                     gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
910
911                 gtk_tree_model_get(gtk_combo_box_get_model
912                                    (GTK_COMBO_BOX(cmb_category)), &iter, 0,
913                                    &poi.cat_id, -1);
914
915                 if (action == ACTION_EDIT_POI) {
916                         /* edit poi */
917                         if (SQLITE_OK !=
918                             sqlite3_bind_text(_stmt_update_poi, 1, poi_label,
919                                               -1, SQLITE_STATIC)
920                             || SQLITE_OK != sqlite3_bind_text(_stmt_update_poi,
921                                                               2, poi_desc, -1,
922                                                               g_free)
923                             || SQLITE_OK != sqlite3_bind_int(_stmt_update_poi,
924                                                              3, poi.cat_id)
925                             || SQLITE_OK != sqlite3_bind_int(_stmt_update_poi,
926                                                              4, poi.poi_id)
927                             || SQLITE_DONE != sqlite3_step(_stmt_update_poi)) {
928                                 MACRO_BANNER_SHOW_INFO(_window,
929                                                        _
930                                                        ("Problem updating POI"));
931                         } else {
932                                 MACRO_MAP_RENDER_DATA();
933                         }
934                         sqlite3_reset(_stmt_update_poi);
935                 } else {
936                         /* add poi */
937                         g_ascii_dtostr(slat1, sizeof(slat1), poi.lat);
938                         g_ascii_dtostr(slon1, sizeof(slon1), poi.lon);
939                         if (SQLITE_OK !=
940                             sqlite3_bind_double(_stmt_insert_poi, 1, poi.lat)
941                             || SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 2, poi.lon)
942                             || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi,
943                                                               3, poi_label, -1,
944                                                               g_free)
945                             || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi,
946                                                               4, poi_desc, -1,
947                                                               g_free)
948                             || SQLITE_OK != sqlite3_bind_int(_stmt_insert_poi,
949                                                              5, poi.cat_id)
950                             || SQLITE_DONE != sqlite3_step(_stmt_insert_poi)) {
951                                 MACRO_BANNER_SHOW_INFO(_window,
952                                                        _("Problem adding POI"));
953                         } else {
954                                 MACRO_MAP_RENDER_DATA();
955                         }
956                         sqlite3_reset(_stmt_insert_poi);
957                 }
958                 break;
959         }
960
961         g_free(dpoi.txt_label);
962
963         g_free(poi.label);
964         g_free(poi.desc);
965         g_free(p_latlon);
966
967         gtk_widget_hide_all(dialog);
968
969         vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
970         return TRUE;
971 }