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