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