]> git.itanic.dy.fi Git - maemo-mapper/blob - src/poi.c
Fixed bugs in POI adding/editing.
[maemo-mapper] / src / poi.c
1 /*
2  * Copyright (C) 2006, 2007 John Costigan.
3  *
4  * POI and GPS-Info code originally written by Cezary Jackiewicz.
5  *
6  * Default map data provided by http://www.openstreetmap.org/
7  *
8  * This file is part of Maemo Mapper.
9  *
10  * Maemo Mapper is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * Maemo Mapper is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Maemo Mapper.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #    include "config.h"
26 #endif
27
28 #define _GNU_SOURCE
29
30 #include <string.h>
31 #include <math.h>
32
33 #ifndef LEGACY
34 #    include <hildon/hildon-help.h>
35 #    include <hildon/hildon-note.h>
36 #    include <hildon/hildon-file-chooser-dialog.h>
37 #    include <hildon/hildon-number-editor.h>
38 #    include <hildon/hildon-banner.h>
39 #else
40 #    include <osso-helplib.h>
41 #    include <hildon-widgets/hildon-note.h>
42 #    include <hildon-widgets/hildon-file-chooser-dialog.h>
43 #    include <hildon-widgets/hildon-number-editor.h>
44 #    include <hildon-widgets/hildon-banner.h>
45 #    include <hildon-widgets/hildon-input-mode-hint.h>
46 #endif
47
48 #include <sqlite3.h>
49
50 #include "types.h"
51 #include "data.h"
52 #include "defines.h"
53
54 #include "display.h"
55 #include "gdk-pixbuf-rotate.h"
56 #include "gpx.h"
57 #include "main.h"
58 #include "poi.h"
59 #include "util.h"
60
61 static sqlite3 *_poi_db = NULL;
62 static sqlite3_stmt *_stmt_browse_poi = NULL;
63 static sqlite3_stmt *_stmt_browsecat_poi = NULL;
64 static sqlite3_stmt *_stmt_select_poi = NULL;
65 static sqlite3_stmt *_stmt_select_nearest_poi = NULL;
66 static sqlite3_stmt *_stmt_insert_poi = NULL;
67 static sqlite3_stmt *_stmt_update_poi = NULL;
68 static sqlite3_stmt *_stmt_delete_poi = NULL;
69 static sqlite3_stmt *_stmt_delete_poi_by_catid = NULL;
70 static sqlite3_stmt *_stmt_nextlabel_poi = NULL;
71 static sqlite3_stmt *_stmt_select_cat = NULL;
72 static sqlite3_stmt *_stmt_insert_cat = NULL;
73 static sqlite3_stmt *_stmt_update_cat = NULL;
74 static sqlite3_stmt *_stmt_delete_cat = NULL;
75 static sqlite3_stmt *_stmt_toggle_cat = NULL;
76 static sqlite3_stmt *_stmt_selall_cat = NULL;
77
78 typedef struct _PoiListInfo PoiListInfo;
79 struct _PoiListInfo
80 {
81     GtkWidget *dialog;
82     GtkWidget *dialog2;
83     GtkTreeViewColumn *select_column;
84     GtkWidget *tree_view;
85     gboolean select_all;
86 };
87
88 typedef struct _OriginToggleInfo OriginToggleInfo;
89 struct _OriginToggleInfo {
90     GtkWidget *rad_use_gps;
91     GtkWidget *rad_use_route;
92     GtkWidget *rad_use_text;
93     GtkWidget *txt_origin;
94     GtkWidget *txt_query;
95 };
96
97 typedef struct _PoiCategoryEditInfo PoiCategoryEditInfo;
98 struct _PoiCategoryEditInfo
99 {
100     GtkWidget *dialog;
101     GtkWidget *cmb_category;
102     gint cat_id;
103     GtkWidget *tree_view;
104 };
105
106 /** Data used during action: add or edit category/poi **/
107 typedef struct _DeletePOI DeletePOI;
108 struct _DeletePOI {
109     GtkWidget *dialog;
110     gchar *txt_label;
111     gint id;
112     gboolean deleted;
113 };
114
115 void
116 poi_db_connect()
117 {
118     gchar buffer[100];
119     gchar **pszResult;
120     gint nRow, nColumn;
121     gchar *db_dirname = NULL;
122     printf("%s()\n", __PRETTY_FUNCTION__);
123
124     if(_poi_db)
125     {
126         sqlite3_close(_poi_db);
127         _poi_db = NULL;
128     }
129
130     if(!_poi_db_filename)
131     {
132         /* Do nothing. */
133     }
134     else if(NULL == (db_dirname = g_path_get_dirname(_poi_db_filename))
135             || (g_mkdir_with_parents(db_dirname, 0755), /* comma operator */
136                 (SQLITE_OK != (sqlite3_open(_poi_db_filename, &_poi_db)))))
137     {
138         gchar buffer2[BUFFER_SIZE];
139         snprintf(buffer2, sizeof(buffer2),
140                 "%s: %s", _("Error with POI database"),
141                 sqlite3_errmsg(_poi_db));
142         sqlite3_close(_poi_db);
143         _poi_db = NULL;
144         popup_error(_window, buffer2);
145     }
146     else if(SQLITE_OK != sqlite3_get_table(_poi_db,
147                 "select label from poi limit 1",
148                 &pszResult, &nRow, &nColumn, NULL))
149     {
150         gchar *create_sql = sqlite3_mprintf(
151                 "create table poi (poi_id integer PRIMARY KEY, lat real, "
152                 "lon real, label text, desc text, cat_id integer);"
153                 "create table category (cat_id integer PRIMARY KEY,"
154                 "label text, desc text, enabled integer);"
155                 /* Add some default categories... */
156                 "insert into category (label, desc, enabled) "
157                     "values ('%q', '%q', 1); "
158                 "insert into category (label, desc, enabled) "
159                     "values ('%q', '%q', 1); "
160                 "insert into category (label, desc, enabled) "
161                     "values ('%q', '%q', 1); "
162                 "insert into category (label, desc, enabled) "
163                     "values ('%q', '%q', 1); "
164                 "insert into category (label, desc, enabled) "
165                     "values ('%q', '%q', 1); "
166                 "insert into category (label, desc, enabled) "
167                     "values ('%q', '%q', 1); "
168                 "insert into category (label, desc, enabled) "
169                     "values ('%q', '%q', 1); "
170                 "insert into category (label, desc, enabled) "
171                     "values ('%q', '%q', 1); "
172                 "insert into category (label, desc, enabled) "
173                     "values ('%q', '%q', 1); "
174                 "insert into category (label, desc, enabled) "
175                     "values ('%q', '%q', 1); "
176                 "insert into category (label, desc, enabled) "
177                     "values ('%q', '%q', 1); ",
178                 _("Service Station"),
179                 _("Stations for purchasing fuel for vehicles."),
180                 _("Residence"),
181                 _("Houses, apartments, or other residences of import."),
182                 _("Restaurant"),
183                 _("Places to eat or drink."),
184                 _("Shopping/Services"),
185                 _("Places to shop or acquire services."),
186                 _("Recreation"),
187                 _("Indoor or Outdoor places to have fun."),
188                 _("Transportation"),
189                 _("Bus stops, airports, train stations, etc."),
190                 _("Lodging"),
191                 _("Places to stay temporarily or for the night."),
192                 _("School"),
193                 _("Elementary schools, college campuses, etc."),
194                 _("Business"),
195                 _("General places of business."),
196                 _("Landmark"),
197                 _("General landmarks."),
198                 _("Other"),
199                 _("Miscellaneous category for everything else."));
200
201         if(SQLITE_OK != sqlite3_exec(_poi_db, create_sql, NULL, NULL, NULL)
202                 && (SQLITE_OK != sqlite3_get_table(_poi_db,
203                         "select label from poi limit 1",
204                         &pszResult, &nRow, &nColumn, NULL)))
205         {
206             snprintf(buffer, sizeof(buffer), "%s:\n%s",
207                     _("Failed to open or create database"),
208                     sqlite3_errmsg(_poi_db));
209             sqlite3_close(_poi_db);
210             _poi_db = NULL;
211             popup_error(_window, buffer);
212         }
213     }
214     else
215         sqlite3_free_table(pszResult);
216
217     g_free(db_dirname);
218
219     if(_poi_db)
220     {
221         /* Prepare our SQL statements. */
222         /* browse poi */
223         sqlite3_prepare(_poi_db,
224                         "select p.poi_id, p.cat_id, p.lat, p.lon,"
225                         " p.label, p.desc, c.label"
226                         " from poi p inner join category c"
227                         "   on p.cat_id = c.cat_id"
228                         " where c.enabled = 1"
229                         " and p.label like $QUERY or p.desc like $QUERY"
230                         " order by (($LAT - p.lat) * ($LAT - p.lat) "
231                                  "+ ($LON - p.lon) * ($LON - p.lon)) DESC",
232                         -1, &_stmt_browse_poi, NULL);
233
234         /* browse poi by category */
235         sqlite3_prepare(_poi_db,
236                         "select p.poi_id, p.cat_id, p.lat, p.lon,"
237                         " p.label, p.desc, c.label"
238                         " from poi p inner join category c"
239                         "   on p.cat_id = c.cat_id"
240                         " where c.enabled = 1"
241                         " and p.cat_id = $CATID"
242                         " and ( p.label like $QUERY or p.desc like $QUERY )"
243                         " order by (($LAT - p.lat) * ($LAT - p.lat) "
244                                  "+ ($LON - p.lon) * ($LON - p.lon)) DESC",
245                         -1, &_stmt_browsecat_poi, NULL);
246
247         /* Prepare our SQL statements. */
248         /* select from poi */
249         sqlite3_prepare(_poi_db,
250                         "select p.lat, p.lon, p.poi_id, p.label, p.desc,"
251                         " p.cat_id, c.label, c.desc"
252                         " from poi p inner join category c"
253                         "    on p.cat_id = c.cat_id"
254                         " where c.enabled = 1"
255                         " and p.lat between ? and ? "
256                         " and p.lon between ? and ? ",
257                         -1, &_stmt_select_poi, NULL);
258
259         /* select nearest pois */
260         sqlite3_prepare(_poi_db,
261                         "select p.poi_id, p.cat_id, p.lat, p.lon,"
262                         " p.label, p.desc, c.label"
263                         " from poi p inner join category c"
264                         "   on p.cat_id = c.cat_id"
265                         " where c.enabled = 1"
266                         " order by (($LAT - p.lat) * ($LAT - p.lat) "
267                                  "+ ($LON - p.lon) * ($LON - p.lon)) limit 1",
268                         -1, &_stmt_select_nearest_poi, NULL);
269
270         /* insert poi */
271         sqlite3_prepare(_poi_db,
272                             "insert into poi (lat, lon, label, desc, cat_id)"
273                             " values (?, ?, ?, ?, ?)",
274                         -1, &_stmt_insert_poi, NULL);
275         /* update poi */
276         sqlite3_prepare(_poi_db,
277                             "update poi set lat = ?, lon = ?, "
278                             "label = ?, desc = ?, cat_id = ? where poi_id = ?",
279                         -1, &_stmt_update_poi, NULL);
280         /* delete from poi */
281         sqlite3_prepare(_poi_db,
282                         " delete from poi where poi_id = ?",
283                         -1, &_stmt_delete_poi, NULL);
284         /* delete from poi by cat_id */
285         sqlite3_prepare(_poi_db,
286                         "delete from poi where cat_id = ?",
287                         -1, &_stmt_delete_poi_by_catid, NULL);
288         /* get next poilabel */
289         sqlite3_prepare(_poi_db,
290                         "select ifnull(max(poi_id) + 1,1) from poi",
291                         -1, &_stmt_nextlabel_poi, NULL);
292
293         /* select from category */
294         sqlite3_prepare(_poi_db,
295                         "select c.label, c.desc, c.enabled"
296                         " from category c where c.cat_id = ?",
297                         -1, &_stmt_select_cat, NULL);
298         /* insert into category */
299         sqlite3_prepare(_poi_db,
300                         "insert into category (label, desc, enabled)"
301                         " values (?, ?, ?)",
302                         -1, &_stmt_insert_cat, NULL);
303         /* update category */
304         sqlite3_prepare(_poi_db,
305                         "update category set label = ?, desc = ?,"
306                         " enabled = ? where cat_id = ?",
307                         -1, &_stmt_update_cat, NULL);
308         /* delete from category */
309         sqlite3_prepare(_poi_db,
310                         "delete from category where cat_id = ?",
311                         -1, &_stmt_delete_cat, NULL);
312         /* enable category */
313         sqlite3_prepare(_poi_db,
314                         "update category set enabled = ?"
315                         " where cat_id = ?",
316                         -1, &_stmt_toggle_cat, NULL);
317         /* select all category */
318         sqlite3_prepare(_poi_db,
319                         "select c.cat_id, c.label, c.desc, c.enabled,"
320                         " count(p.poi_id)"
321                         " from category c"
322                         " left outer join poi p on c.cat_id = p.cat_id"
323                         " group by c.cat_id, c.label, c.desc, c.enabled "
324                         " order by c.label",
325                         -1, &_stmt_selall_cat, NULL);
326     }
327
328     _poi_enabled = _poi_db != NULL;
329
330     gtk_widget_set_sensitive(_menu_poi_item, _poi_enabled);
331     gtk_widget_set_sensitive(_cmenu_loc_add_poi_item, _poi_enabled);
332     gtk_widget_set_sensitive(_cmenu_loc_download_poi_item, _poi_enabled);
333     gtk_widget_set_sensitive(_cmenu_loc_browse_poi_item, _poi_enabled);
334     gtk_widget_set_sensitive(_cmenu_way_add_poi_item, _poi_enabled);
335     gtk_widget_set_sensitive(_cmenu_poi_submenu, _poi_enabled);
336
337     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
338 }
339
340 gboolean
341 get_nearest_poi(gint unitx, gint unity, PoiInfo *poi)
342 {
343     printf("%s(%d, %d)\n", __PRETTY_FUNCTION__, unitx, unity);
344     gboolean result;
345     gdouble lat, lon;
346     unit2latlon(unitx, unity, lat, lon);
347
348     if(SQLITE_OK == sqlite3_bind_double(_stmt_select_nearest_poi, 1, lat)
349     && SQLITE_OK == sqlite3_bind_double(_stmt_select_nearest_poi, 2, lon)
350         && SQLITE_ROW == sqlite3_step(_stmt_select_nearest_poi))
351     {
352         poi->poi_id = sqlite3_column_int(_stmt_select_nearest_poi, 0);
353         poi->cat_id = sqlite3_column_int(_stmt_select_nearest_poi, 1);
354         poi->lat = sqlite3_column_double(_stmt_select_nearest_poi, 2);
355         poi->lon = sqlite3_column_double(_stmt_select_nearest_poi, 3);
356         poi->label =g_strdup(sqlite3_column_text(_stmt_select_nearest_poi, 4));
357         poi->desc = g_strdup(sqlite3_column_text(_stmt_select_nearest_poi, 5));
358         poi->clabel=g_strdup(sqlite3_column_text(_stmt_select_nearest_poi, 6));
359         result = TRUE;
360     }
361     else
362         result = FALSE;
363     sqlite3_reset(_stmt_select_nearest_poi);
364     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, result);
365     return result;
366 }
367
368 gboolean
369 select_poi(gint unitx, gint unity, PoiInfo *poi, gboolean quick)
370 {
371     gint x, y;
372     gdouble lat1, lon1, lat2, lon2;
373     static GtkWidget *dialog = NULL;
374     static GtkWidget *list = NULL;
375     static GtkWidget *sw = NULL;
376     static GtkTreeViewColumn *column = NULL;
377     static GtkCellRenderer *renderer = NULL;
378     GtkListStore *store = NULL;
379     GtkTreeIter iter;
380     gboolean selected = FALSE;
381     gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
382     gint num_cats = 0;
383     printf("%s()\n", __PRETTY_FUNCTION__);
384
385     x = unitx - pixel2unit(3 * _draw_width);
386     y = unity + pixel2unit(3 * _draw_width);
387     unit2latlon(x, y, lat1, lon1);
388
389     x = unitx + pixel2unit(3 * _draw_width);
390     y = unity - pixel2unit(3 * _draw_width);
391     unit2latlon(x, y, lat2, lon2);
392
393     if(SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 1, lat1) ||
394           SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 2, lat2) ||
395           SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 3, lon1) ||
396           SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 4, lon2))
397     {
398         g_printerr("Failed to bind values for _stmt_select_poi\n");
399         return FALSE;
400     }
401
402     /* Initialize store. */
403     store = gtk_list_store_new(POI_NUM_COLUMNS,
404                                G_TYPE_BOOLEAN,/* Selected */
405                                G_TYPE_INT,    /* POI ID */
406                                G_TYPE_INT,    /* Category ID */
407                                G_TYPE_DOUBLE,  /* Latitude */
408                                G_TYPE_DOUBLE,  /* Longitude */
409                                G_TYPE_STRING, /* Lat/Lon */
410                                G_TYPE_FLOAT,  /* Bearing */
411                                G_TYPE_FLOAT,  /* Distance */
412                                G_TYPE_STRING, /* POI Label */
413                                G_TYPE_STRING, /* POI Desc. */
414                                G_TYPE_STRING);/* Category Label */
415
416     while(SQLITE_ROW == sqlite3_step(_stmt_select_poi))
417     {
418         gdouble lat, lon;
419         lat = sqlite3_column_double(_stmt_select_poi, 0);
420         lon = sqlite3_column_double(_stmt_select_poi, 1);
421         lat_format(lat, tmp1);
422         lon_format(lon, tmp2);
423         gtk_list_store_append(store, &iter);
424         gtk_list_store_set(store, &iter,
425                 POI_POIID, sqlite3_column_int(_stmt_select_poi, 2),
426                 POI_CATID, sqlite3_column_int(_stmt_select_poi, 5),
427                 POI_LAT, lat,
428                 POI_LON, lon,
429                 POI_LATLON, g_strdup_printf("%s, %s", tmp1, tmp2),
430                 POI_LABEL, sqlite3_column_text(_stmt_select_poi, 3),
431                 POI_DESC, sqlite3_column_text(_stmt_select_poi, 4),
432                 POI_CLABEL, sqlite3_column_text(_stmt_select_poi, 6),
433                 -1);
434         num_cats++;
435     }
436     sqlite3_reset(_stmt_select_poi);
437
438     switch(num_cats)
439     {
440         case 0:
441             g_object_unref(G_OBJECT(store));
442             if(!quick)
443             {
444                 MACRO_BANNER_SHOW_INFO(_window, _("No POIs found."));
445             }
446             return FALSE;
447             break;
448         case 1:
449             /* iter is still set to the most-recently added POI. */
450             gtk_tree_model_get(GTK_TREE_MODEL(store),
451                 &iter,
452                 POI_POIID, &(poi->poi_id),
453                 POI_CATID, &(poi->cat_id),
454                 POI_LAT, &(poi->lat),
455                 POI_LON, &(poi->lon),
456                 POI_LABEL, &(poi->label),
457                 POI_DESC, &(poi->desc),
458                 POI_CLABEL, &(poi->clabel),
459                 -1);
460             g_object_unref(G_OBJECT(store));
461             return TRUE;
462             break;
463         default:
464             if(quick)
465             {
466                 g_object_unref(G_OBJECT(store));
467                 return get_nearest_poi(unitx, unity, poi);
468             }
469     }
470
471     /* There are at least 2 matching POI's - let the user select one. */
472     if(dialog == NULL)
473     {
474         dialog = gtk_dialog_new_with_buttons(_("Select POI"),
475                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
476                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
477                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
478                 NULL);
479
480         gtk_window_set_default_size(GTK_WINDOW(dialog), 500, 300);
481
482         sw = gtk_scrolled_window_new (NULL, NULL);
483         gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
484                 GTK_SHADOW_ETCHED_IN);
485         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
486                 GTK_POLICY_NEVER,
487                 GTK_POLICY_AUTOMATIC);
488         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
489                 sw, TRUE, TRUE, 0);
490
491         list = gtk_tree_view_new();
492         gtk_container_add(GTK_CONTAINER(sw), list);
493
494         gtk_tree_selection_set_mode(
495                 gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
496                 GTK_SELECTION_SINGLE);
497         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(list), TRUE);
498
499         renderer = gtk_cell_renderer_text_new();
500         column = gtk_tree_view_column_new_with_attributes(
501                 _("Location"), renderer, "text", POI_LATLON, NULL);
502         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
503
504         renderer = gtk_cell_renderer_text_new();
505         column = gtk_tree_view_column_new_with_attributes(
506                 _("Label"), renderer, "text", POI_LABEL, NULL);
507         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
508
509         renderer = gtk_cell_renderer_text_new();
510         column = gtk_tree_view_column_new_with_attributes(
511                 _("Category"), renderer, "text", POI_CLABEL, NULL);
512         gtk_tree_view_append_column(GTK_TREE_VIEW(list), column);
513     }
514
515     gtk_tree_view_set_model(GTK_TREE_VIEW(list), GTK_TREE_MODEL(store));
516     g_object_unref(G_OBJECT(store));
517
518     gtk_widget_show_all(dialog);
519
520     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
521     {
522         if(gtk_tree_selection_get_selected(
523                     gtk_tree_view_get_selection(GTK_TREE_VIEW(list)),
524                     NULL, &iter))
525         {
526             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
527                 POI_POIID, &(poi->poi_id),
528                 POI_CATID, &(poi->cat_id),
529                 POI_LAT, &(poi->lat),
530                 POI_LON, &(poi->lon),
531                 POI_LABEL, &(poi->label),
532                 POI_DESC, &(poi->desc),
533                 POI_CLABEL, &(poi->clabel),
534                 -1);
535             selected = TRUE;
536             break;
537         }
538         else
539             popup_error(dialog, _("Select one POI from the list."));
540     }
541
542     map_force_redraw();
543
544     gtk_widget_hide(dialog);
545
546     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, selected);
547     return selected;
548 }
549
550 static gboolean
551 category_delete(GtkWidget *widget, DeletePOI *dpoi)
552 {
553     GtkWidget *confirm;
554     gint i;
555     gchar *buffer;
556     printf("%s()\n", __PRETTY_FUNCTION__);
557
558     buffer = g_strdup_printf("%s\n\t%s\n%s",
559             _("Delete category?"),
560             dpoi->txt_label,
561             _("WARNING: All POIs in that category will also be deleted!"));
562     confirm = hildon_note_new_confirmation(GTK_WINDOW(dpoi->dialog), buffer);
563     g_free(buffer);
564     i = gtk_dialog_run(GTK_DIALOG(confirm));
565     gtk_widget_destroy(GTK_WIDGET(confirm));
566
567     if(i == GTK_RESPONSE_OK)
568     {
569         /* delete dpoi->poi_id */
570         if(SQLITE_OK != sqlite3_bind_int(_stmt_delete_poi_by_catid, 1,
571                     dpoi->id) ||
572            SQLITE_DONE != sqlite3_step(_stmt_delete_poi_by_catid))
573         {
574             MACRO_BANNER_SHOW_INFO(dpoi->dialog, _("Error deleting POI"));
575             sqlite3_reset(_stmt_delete_poi_by_catid);
576             return FALSE;
577         }
578         sqlite3_reset(_stmt_delete_poi_by_catid);
579
580         if(SQLITE_OK != sqlite3_bind_int(_stmt_delete_cat, 1, dpoi->id) ||
581            SQLITE_DONE != sqlite3_step(_stmt_delete_cat))
582         {
583             MACRO_BANNER_SHOW_INFO(dpoi->dialog, _("Error deleting category"));
584             sqlite3_reset(_stmt_delete_cat);
585             return FALSE;
586         }
587         sqlite3_reset(_stmt_delete_cat);
588
589         map_force_redraw();
590     }
591     gtk_widget_destroy(confirm);
592
593     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
594     return TRUE;
595 }
596
597 gboolean
598 category_edit_dialog(GtkWidget *parent, gint cat_id)
599 {
600     gchar *cat_label = NULL, *cat_desc = NULL;
601     gint cat_enabled;
602     GtkWidget *dialog;
603     GtkWidget *table;
604     GtkWidget *label;
605     GtkWidget *txt_label;
606     GtkWidget *txt_desc;
607     GtkWidget *btn_delete = NULL;
608     GtkWidget *txt_scroll;
609     GtkWidget *chk_enabled;
610     GtkTextBuffer *desc_txt;
611     GtkTextIter begin, end;
612     gboolean results = TRUE;
613     DeletePOI dpoi = {NULL, NULL, 0};
614     printf("%s()\n", __PRETTY_FUNCTION__);
615
616     if(cat_id > 0)
617     {
618         if(SQLITE_OK != sqlite3_bind_double(_stmt_select_cat, 1, cat_id) ||
619            SQLITE_ROW != sqlite3_step(_stmt_select_cat))
620         {
621             vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
622             sqlite3_reset(_stmt_select_cat);
623             return FALSE;
624         }
625
626         cat_label = g_strdup(sqlite3_column_text(_stmt_select_cat, 0));
627         cat_desc = g_strdup(sqlite3_column_text(_stmt_select_cat, 1));
628         cat_enabled = sqlite3_column_int(_stmt_select_cat, 2);
629
630         sqlite3_reset(_stmt_select_cat);
631
632         dialog = gtk_dialog_new_with_buttons(_("Edit Category"),
633             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
634             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
635             NULL);
636
637         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
638                 btn_delete = gtk_button_new_with_label(_("Delete...")));
639
640         dpoi.dialog = dialog;
641         dpoi.txt_label = g_strdup(cat_label);
642         dpoi.id = cat_id;
643         dpoi.deleted = FALSE;
644
645         g_signal_connect(G_OBJECT(btn_delete), "clicked",
646                           G_CALLBACK(category_delete), &dpoi);
647
648         gtk_dialog_add_button(GTK_DIALOG(dialog),
649                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
650     }
651     else
652     {
653         cat_enabled = 1;
654         cat_label = g_strdup("");
655         cat_id = -1;
656         cat_desc = g_strdup("");
657
658         dialog = gtk_dialog_new_with_buttons(_("Add Category"),
659             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
660             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
661             GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
662             NULL);
663     }
664
665     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
666             table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
667
668     gtk_table_attach(GTK_TABLE(table),
669             label = gtk_label_new(_("Label")),
670             0, 1, 0, 1, GTK_FILL, 0, 2, 4);
671     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
672     gtk_table_attach(GTK_TABLE(table),
673             txt_label = gtk_entry_new(),
674             1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
675
676     gtk_table_attach(GTK_TABLE(table),
677             label = gtk_label_new(_("Description")),
678             0, 1, 1, 2, GTK_FILL, 0, 2, 4);
679     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
680
681     txt_scroll = gtk_scrolled_window_new(NULL, NULL);
682     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
683                                    GTK_SHADOW_IN);
684     gtk_table_attach(GTK_TABLE(table),
685             txt_scroll,
686             1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
687
688     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
689                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
690
691     txt_desc = gtk_text_view_new();
692     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
693
694     gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
695     gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
696
697     desc_txt = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
698
699     gtk_table_attach(GTK_TABLE(table),
700             chk_enabled = gtk_check_button_new_with_label(
701                 _("Enabled")),
702             0, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
703
704     /* label */
705     gtk_entry_set_text(GTK_ENTRY(txt_label), cat_label);
706
707     /* desc */
708     gtk_text_buffer_set_text(desc_txt, cat_desc, -1);
709
710     /* enabled */
711     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk_enabled),
712             (cat_enabled == 1 ? TRUE : FALSE));
713
714     g_free(cat_label);
715     cat_label = NULL;
716     g_free(cat_desc);
717     cat_desc = NULL;
718
719     gtk_widget_show_all(dialog);
720
721     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
722     {
723         if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
724             cat_label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
725         else
726         {
727             popup_error(dialog, _("Please specify a name for the category."));
728             continue;
729         }
730
731         gtk_text_buffer_get_iter_at_offset(desc_txt, &begin,0 );
732         gtk_text_buffer_get_end_iter (desc_txt, &end);
733         cat_desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
734
735         cat_enabled = (gtk_toggle_button_get_active(
736                 GTK_TOGGLE_BUTTON(chk_enabled)) ? 1 : 0);
737
738         if(cat_id > 0)
739         {
740             /* edit category */
741             if(SQLITE_OK != sqlite3_bind_text(_stmt_update_cat, 1, cat_label,
742                         -1, g_free) ||
743                SQLITE_OK != sqlite3_bind_text(_stmt_update_cat, 2, cat_desc,
744                         -1, g_free) ||
745                SQLITE_OK != sqlite3_bind_int(_stmt_update_cat, 3,cat_enabled)||
746                SQLITE_OK != sqlite3_bind_int(_stmt_update_cat, 4, cat_id) ||
747                SQLITE_DONE != sqlite3_step(_stmt_update_cat))
748             {
749                 MACRO_BANNER_SHOW_INFO(parent,_("Error updating category"));
750                 results = FALSE;
751             }
752             sqlite3_reset(_stmt_update_cat);
753         }
754         else
755         {
756             /* add category */
757             if(SQLITE_OK != sqlite3_bind_text(_stmt_insert_cat, 1, cat_label,
758                         -1, g_free) ||
759                SQLITE_OK != sqlite3_bind_text(_stmt_insert_cat, 2, cat_desc,
760                         -1, g_free) ||
761                SQLITE_OK != sqlite3_bind_int(_stmt_insert_cat, 3,cat_enabled)||
762                SQLITE_DONE != sqlite3_step(_stmt_insert_cat))
763             {
764                 MACRO_BANNER_SHOW_INFO(parent, _("Error adding category"));
765                 results = FALSE;
766             }
767             sqlite3_reset(_stmt_insert_cat);
768         }
769         break;
770     }
771
772     g_free(dpoi.txt_label);
773
774     g_object_unref (desc_txt);
775
776     if(results)
777         map_force_redraw();
778
779     gtk_widget_hide(dialog);
780
781     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
782     return results;
783 }
784
785 static void
786 category_toggled(GtkCellRendererToggle *cell, gchar *path, GtkListStore *data)
787 {
788     GtkTreeIter iter;
789     gboolean cat_enabled;
790     gint cat_id;
791     printf("%s()\n", __PRETTY_FUNCTION__);
792
793     GtkTreeModel *model = GTK_TREE_MODEL(data);
794     if( !gtk_tree_model_get_iter_from_string(model, &iter, path) )
795         return;
796
797     gtk_tree_model_get(model, &iter,
798             CAT_ENABLED, &cat_enabled,
799             CAT_ID, &cat_id,
800             -1);
801
802     cat_enabled ^= 1;
803
804     if(SQLITE_OK != sqlite3_bind_int(_stmt_toggle_cat, 1, cat_enabled) ||
805        SQLITE_OK != sqlite3_bind_int(_stmt_toggle_cat, 2, cat_id) ||
806        SQLITE_DONE != sqlite3_step(_stmt_toggle_cat))
807     {
808         MACRO_BANNER_SHOW_INFO(_window, _("Error updating Category"));
809     }
810     else
811     {
812         gtk_list_store_set(GTK_LIST_STORE(model), &iter,
813                    CAT_ENABLED, cat_enabled, -1);
814         map_force_redraw();
815     }
816
817     sqlite3_reset(_stmt_toggle_cat);
818
819     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
820 }
821
822 static GtkListStore*
823 generate_store()
824 {
825     GtkTreeIter iter;
826     GtkListStore *store;
827     printf("%s()\n", __PRETTY_FUNCTION__);
828
829     store = gtk_list_store_new(CAT_NUM_COLUMNS,
830                                G_TYPE_UINT,
831                                G_TYPE_BOOLEAN,
832                                G_TYPE_STRING,
833                                G_TYPE_STRING,
834                                G_TYPE_UINT);
835
836     while(SQLITE_ROW == sqlite3_step(_stmt_selall_cat))
837     {
838         gtk_list_store_append(store, &iter);
839         gtk_list_store_set(store, &iter,
840                 CAT_ID, sqlite3_column_int(_stmt_selall_cat, 0),
841                 CAT_ENABLED, sqlite3_column_int(_stmt_selall_cat, 3),
842                 CAT_LABEL, sqlite3_column_text(_stmt_selall_cat, 1),
843                 CAT_DESC, sqlite3_column_text(_stmt_selall_cat, 2),
844                 CAT_POI_CNT, sqlite3_column_int(_stmt_selall_cat, 4),
845                 -1);
846     }
847     sqlite3_reset(_stmt_selall_cat);
848
849     vprintf("%s(): return %p\n", __PRETTY_FUNCTION__, store);
850     return store;
851 }
852
853 static gboolean
854 category_add(GtkWidget *widget, PoiCategoryEditInfo *pcedit)
855 {
856     GtkListStore *store;
857     printf("%s()\n", __PRETTY_FUNCTION__);
858
859     if(category_edit_dialog(pcedit->dialog, 0))
860     {
861         store = generate_store();
862         gtk_tree_view_set_model(
863                 GTK_TREE_VIEW(pcedit->tree_view),
864                 GTK_TREE_MODEL(store));
865         g_object_unref(G_OBJECT(store));
866     }
867     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
868     return TRUE;
869 }
870
871 static gboolean
872 category_edit(GtkWidget *widget, PoiCategoryEditInfo *pcedit)
873 {
874     GtkTreeIter iter;
875     GtkTreeModel *store;
876     GtkTreeSelection *selection;
877     printf("%s()\n", __PRETTY_FUNCTION__);
878
879     store = gtk_tree_view_get_model(GTK_TREE_VIEW(pcedit->tree_view));
880     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pcedit->tree_view));
881     if(gtk_tree_selection_get_selected(selection, &store, &iter))
882     {
883         GValue val;
884         memset(&val, 0, sizeof(val));
885         gtk_tree_model_get_value(store, &iter, 0, &val);
886         if(category_edit_dialog(pcedit->dialog, g_value_get_uint(&val)))
887         {
888             GtkListStore *new_store = generate_store();
889             gtk_tree_view_set_model(
890                     GTK_TREE_VIEW(pcedit->tree_view),
891                     GTK_TREE_MODEL(new_store));
892             g_object_unref(G_OBJECT(new_store));
893         }
894     }
895     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
896     return TRUE;
897 }
898
899 gboolean
900 category_list_dialog(GtkWidget *parent)
901 {
902     static GtkWidget *dialog = NULL;
903     static GtkWidget *tree_view = NULL;
904     static GtkWidget *sw = NULL;
905     static GtkWidget *btn_edit = NULL;
906     static GtkWidget *btn_add = NULL;
907     static GtkTreeViewColumn *column = NULL;
908     static GtkCellRenderer *renderer = NULL;
909     static GtkListStore *store;
910     static PoiCategoryEditInfo pcedit;
911     printf("%s()\n", __PRETTY_FUNCTION__);
912
913     store = generate_store();
914
915     if(!store)
916         return TRUE;
917
918     dialog = gtk_dialog_new_with_buttons(_("POI Categories"),
919             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
920             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
921             NULL);
922
923     /* Enable the help button. */
924 #ifndef LEGACY
925     hildon_help_dialog_help_enable(
926 #else
927     ossohelp_dialog_help_enable(
928 #endif
929             GTK_DIALOG(dialog), HELP_ID_POICAT, _osso);
930
931     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
932             btn_edit = gtk_button_new_with_label(_("Edit...")));
933
934     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
935             btn_add = gtk_button_new_with_label(_("Add...")));
936
937     sw = gtk_scrolled_window_new(NULL, NULL);
938     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (sw),
939                   GTK_POLICY_NEVER,
940                   GTK_POLICY_AUTOMATIC);
941     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
942             sw, TRUE, TRUE, 0);
943
944     tree_view = gtk_tree_view_new();
945     /* Maemo-related? */
946     g_object_set(tree_view, "allow-checkbox-mode", FALSE, NULL);
947     gtk_container_add (GTK_CONTAINER (sw), tree_view);
948
949     gtk_tree_selection_set_mode(
950             gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)),
951             GTK_SELECTION_SINGLE);
952     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), TRUE);
953
954     renderer = gtk_cell_renderer_text_new();
955     column = gtk_tree_view_column_new_with_attributes(
956             _("ID"), renderer, "text", CAT_ID, NULL);
957     gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
958     gtk_tree_view_column_set_max_width (column, 1);
959
960     renderer = gtk_cell_renderer_toggle_new();
961     g_signal_connect (renderer, "toggled",
962             G_CALLBACK (category_toggled), store);
963     column = gtk_tree_view_column_new_with_attributes(
964             _("Enabled"), renderer, "active", CAT_ENABLED, NULL);
965     gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
966
967     renderer = gtk_cell_renderer_text_new();
968     column = gtk_tree_view_column_new_with_attributes(
969             _("Label"), renderer, "text", CAT_LABEL, NULL);
970     gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
971
972     renderer = gtk_cell_renderer_text_new();
973     column = gtk_tree_view_column_new_with_attributes(
974             _("Description"), renderer, "text", CAT_DESC, NULL);
975     gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
976
977     renderer = gtk_cell_renderer_text_new();
978     column = gtk_tree_view_column_new_with_attributes(
979             _("# POIs"), renderer, "text", CAT_POI_CNT, NULL);
980     gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);
981
982     gtk_window_set_default_size(GTK_WINDOW(dialog), -1, 400);
983
984     pcedit.dialog = dialog;
985     pcedit.tree_view = tree_view;
986
987     g_signal_connect(G_OBJECT(btn_edit), "clicked",
988             G_CALLBACK(category_edit), &pcedit);
989
990     g_signal_connect(G_OBJECT(btn_add), "clicked",
991             G_CALLBACK(category_add), &pcedit);
992
993     gtk_tree_view_set_model(GTK_TREE_VIEW(tree_view), GTK_TREE_MODEL(store));
994     g_object_unref(G_OBJECT(store));
995
996     gtk_widget_show_all(dialog);
997
998     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
999     {
1000         break;
1001     }
1002
1003     gtk_widget_destroy(dialog);
1004
1005     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1006     return TRUE;
1007 }
1008
1009 static gboolean
1010 poi_delete(GtkWidget *widget, DeletePOI *dpoi)
1011 {
1012     GtkWidget *confirm;
1013     gint i;
1014     gchar *buffer;
1015     printf("%s()\n", __PRETTY_FUNCTION__);
1016
1017     buffer = g_strdup_printf("%s\n%s", _("Delete POI?"), dpoi->txt_label);
1018     confirm = hildon_note_new_confirmation(GTK_WINDOW(dpoi->dialog), buffer);
1019     g_free(buffer);
1020     i = gtk_dialog_run(GTK_DIALOG(confirm));
1021     gtk_widget_destroy(GTK_WIDGET(confirm));
1022
1023     if(i == GTK_RESPONSE_OK)
1024     {
1025         if(SQLITE_OK != sqlite3_bind_int(_stmt_delete_poi, 1, dpoi->id) ||
1026            SQLITE_DONE != sqlite3_step(_stmt_delete_poi))
1027         {
1028             MACRO_BANNER_SHOW_INFO(dpoi->dialog, _("Error deleting POI"));
1029         }
1030         else
1031         {
1032             dpoi->deleted = TRUE;
1033             gtk_widget_hide(dpoi->dialog);
1034             map_force_redraw();
1035         }
1036         sqlite3_reset(_stmt_delete_poi);
1037     }
1038
1039     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1040     return TRUE;
1041 }
1042
1043 static gboolean
1044 poi_populate_categories(GtkListStore *store, gint cat_id,
1045         GtkTreeIter *out_active)
1046 {
1047     gboolean has_active = FALSE;
1048     printf("%s()\n", __PRETTY_FUNCTION__);
1049
1050     gtk_list_store_clear(store);
1051
1052     while(SQLITE_ROW == sqlite3_step(_stmt_selall_cat))
1053     {
1054         GtkTreeIter iter;
1055         gint cid = sqlite3_column_int(_stmt_selall_cat, 0);
1056         const gchar *clab = sqlite3_column_text(_stmt_selall_cat, 1);
1057
1058         gtk_list_store_append(store, &iter);
1059         gtk_list_store_set(store, &iter, 0, cid, 1, clab, -1);
1060
1061         if(cid == cat_id || !has_active)
1062         {
1063             if(out_active)
1064                 *out_active = iter;
1065             has_active = TRUE;
1066         }
1067     }
1068     sqlite3_reset(_stmt_selall_cat);
1069
1070     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1071     return has_active;
1072 }
1073
1074 static gboolean
1075 poi_edit_cat(GtkWidget *widget, PoiCategoryEditInfo *data)
1076 {
1077     printf("%s()\n", __PRETTY_FUNCTION__);
1078     if(category_list_dialog(data->dialog))
1079     {
1080         GtkTreeIter active;
1081         if(poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1082                         GTK_COMBO_BOX(data->cmb_category))),
1083                 data->cat_id, &active))
1084         {
1085             gtk_combo_box_set_active_iter(
1086                     GTK_COMBO_BOX(data->cmb_category), &active);
1087         }
1088     }
1089     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1090     return TRUE;
1091 }
1092
1093 static GtkWidget*
1094 poi_create_cat_combo()
1095 {
1096     GtkWidget *cmb_category;
1097     GtkTreeModel *model;
1098     printf("%s()\n", __PRETTY_FUNCTION__);
1099
1100     model = GTK_TREE_MODEL(gtk_list_store_new(2,
1101                 G_TYPE_INT,      /* Category ID */
1102                 G_TYPE_STRING)); /* Category Label */
1103     cmb_category = gtk_combo_box_new_with_model(model);
1104     g_object_unref(model);
1105
1106     /* Set up the view for the combo box. */
1107     {
1108         GtkCellRenderer *renderer;
1109         GtkTreeIter active;
1110         renderer = gtk_cell_renderer_text_new();
1111         gtk_cell_layout_pack_start(
1112                 GTK_CELL_LAYOUT(cmb_category), renderer, TRUE);
1113         gtk_cell_layout_set_attributes(
1114                 GTK_CELL_LAYOUT(cmb_category), renderer, "text", 1, NULL);
1115
1116         poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1117                         GTK_COMBO_BOX(cmb_category))), -1, &active);
1118     }
1119     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1120     return cmb_category;
1121 }
1122
1123 gboolean
1124 poi_add_dialog(GtkWidget *parent, gint unitx, gint unity)
1125 {
1126     gchar buffer[16];
1127     static PoiInfo poi;
1128     static GtkWidget *dialog;
1129     static GtkWidget *table;
1130     static GtkWidget *label;
1131     static GtkWidget *txt_label;
1132     static GtkWidget *txt_lat;
1133     static GtkWidget *txt_lon;
1134     static GtkWidget *cmb_category;
1135     static GtkWidget *txt_desc;
1136     static GtkWidget *btn_catedit;
1137     static GtkWidget *hbox;
1138     static GtkWidget *txt_scroll;
1139     static GtkTextBuffer *desc_txt;
1140     static GtkTextIter begin, end;
1141     static DeletePOI dpoi = {NULL, NULL, 0};
1142     static PoiCategoryEditInfo pcedit;
1143     printf("%s()\n", __PRETTY_FUNCTION__);
1144
1145     if(dialog == NULL)
1146     {
1147         dialog = gtk_dialog_new_with_buttons(_("Add POI"),
1148             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
1149             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1150             GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1151             NULL);
1152
1153         /* Set the lat/lon strings. */
1154         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1155                 table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
1156
1157         gtk_table_attach(GTK_TABLE(table),
1158                 label = gtk_label_new(_("Lat")),
1159                 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1160         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1161         gtk_table_attach(GTK_TABLE(table),
1162                 txt_lat = gtk_entry_new(),
1163                 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1164
1165         gtk_table_attach(GTK_TABLE(table),
1166                 label = gtk_label_new(_("Lon")),
1167                 2, 3, 0, 1, GTK_FILL, 0, 2, 0);
1168         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1169         gtk_table_attach(GTK_TABLE(table),
1170                 txt_lon = gtk_entry_new(),
1171                 3, 4, 0, 1, GTK_FILL, 0, 2, 0);
1172
1173         gtk_table_attach(GTK_TABLE(table),
1174                 label = gtk_label_new(_("Label")),
1175                 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1176         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1177         gtk_table_attach(GTK_TABLE(table),
1178                 txt_label = gtk_entry_new(),
1179                 1, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1180
1181         gtk_table_attach(GTK_TABLE(table),
1182                 label = gtk_label_new(_("Category")),
1183                 0, 1, 3, 4, GTK_FILL, 0, 2, 0);
1184         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1185         gtk_table_attach(GTK_TABLE(table),
1186                 hbox = gtk_hbox_new(FALSE, 4),
1187                 1, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1188         gtk_box_pack_start(GTK_BOX(hbox),
1189                 cmb_category = poi_create_cat_combo(),
1190                 FALSE, FALSE, 0);
1191
1192         gtk_box_pack_start(GTK_BOX(hbox),
1193                 btn_catedit = gtk_button_new_with_label(
1194                     _("Edit Categories...")),
1195                 FALSE, FALSE, 0);
1196
1197         gtk_table_attach(GTK_TABLE(table),
1198                 label = gtk_label_new(_("Description")),
1199                 0, 1, 5, 6, GTK_FILL, GTK_FILL, 2, 0);
1200         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.0f);
1201
1202         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
1203         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
1204                 GTK_SHADOW_IN);
1205         gtk_table_attach(GTK_TABLE(table),
1206                 txt_scroll,
1207                 1, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1208
1209         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
1210                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1211
1212         txt_desc = gtk_text_view_new ();
1213         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
1214
1215         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
1216         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 550, 120);
1217
1218         desc_txt = gtk_text_view_get_buffer(GTK_TEXT_VIEW (txt_desc));
1219
1220         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
1221                 G_CALLBACK(poi_edit_cat), &pcedit);
1222     }
1223
1224     poi.poi_id = -1;
1225     poi.cat_id = -1;
1226     poi.clabel = NULL;
1227     poi.desc = g_strdup("");
1228     unit2latlon(unitx, unity, poi.lat, poi.lon);
1229
1230     /* Lat/Lon */
1231     {
1232         gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
1233
1234         lat_format(poi.lat, tmp1);
1235         lon_format(poi.lon, tmp2);
1236
1237         gtk_entry_set_text(GTK_ENTRY(txt_lat), tmp1);
1238         gtk_entry_set_text(GTK_ENTRY(txt_lon), tmp2);
1239     }
1240
1241     /* Label */
1242     if(SQLITE_ROW == sqlite3_step(_stmt_nextlabel_poi))
1243         poi.label = g_strdup_printf("Point%06d",
1244                 sqlite3_column_int(_stmt_nextlabel_poi, 0));
1245     else
1246         poi.label = g_strdup("");
1247     sqlite3_reset(_stmt_nextlabel_poi);
1248     gtk_entry_set_text(GTK_ENTRY(txt_label), poi.label);
1249
1250     /* POI Desc. */
1251     gtk_text_buffer_set_text(desc_txt, "", -1);
1252
1253     /* Category. */
1254     {
1255         GtkTreeIter iter;
1256         gint cat_id = -1;
1257         gboolean had_cat_id = FALSE;
1258
1259         if(gtk_combo_box_get_active_iter(
1260                 GTK_COMBO_BOX(cmb_category), &iter))
1261         {
1262             gtk_tree_model_get(
1263                     gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),&iter,
1264                     0, &cat_id,
1265                     -1);
1266             had_cat_id = TRUE;
1267         }
1268         gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(
1269                         GTK_COMBO_BOX(cmb_category))));
1270         if(poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1271                     GTK_COMBO_BOX(cmb_category))), cat_id, &iter)
1272                 && had_cat_id)
1273         {
1274             gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
1275         }
1276     }
1277
1278     pcedit.dialog = dialog;
1279     pcedit.cmb_category = cmb_category;
1280     pcedit.cat_id = poi.cat_id;
1281
1282     gtk_widget_show_all(dialog);
1283
1284     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1285     {
1286         GtkTreeIter iter;
1287         const gchar *text;
1288         gchar *error_check;
1289
1290         text = gtk_entry_get_text(GTK_ENTRY(txt_lat));
1291         poi.lat = strdmstod(text, &error_check);
1292         if(text == error_check || poi.lat < -90. || poi.lat > 90.) {
1293             popup_error(dialog, _("Invalid Latitude"));
1294             continue;
1295         }
1296
1297         text = gtk_entry_get_text(GTK_ENTRY(txt_lon));
1298         poi.lon = strdmstod(text, &error_check);
1299         if(text == error_check || poi.lon < -180. || poi.lon > 180.) {
1300             popup_error(dialog, _("Invalid Longitude"));
1301             continue;
1302         }
1303
1304         if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
1305         {
1306             if(poi.label)
1307                 g_free(poi.label);
1308             poi.label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
1309         }
1310         else
1311         {
1312             popup_error(dialog, _("Please specify a name."));
1313             continue;
1314         }
1315
1316         if(!gtk_combo_box_get_active_iter(
1317                 GTK_COMBO_BOX(cmb_category), &iter))
1318         {
1319             popup_error(dialog, _("Please specify a category."));
1320             continue;
1321         }
1322
1323         gtk_text_buffer_get_iter_at_offset(desc_txt, &begin,0 );
1324         gtk_text_buffer_get_end_iter (desc_txt, &end);
1325         if(poi.desc)
1326             g_free(poi.desc);
1327         poi.desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
1328
1329         if(poi.clabel)
1330             g_free(poi.clabel);
1331         gtk_tree_model_get(
1332                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
1333                 0, &poi.cat_id,
1334                 1, &poi.clabel,
1335                 -1);
1336
1337         /* add poi */
1338         if(SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 1, poi.lat)
1339         || SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 2, poi.lon)
1340         || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 3, poi.label,
1341                -1, g_free)
1342         || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 4, poi.desc,
1343                -1, g_free)
1344         || SQLITE_OK != sqlite3_bind_int(_stmt_insert_poi, 5, poi.cat_id)
1345         || SQLITE_DONE != sqlite3_step(_stmt_insert_poi))
1346         {
1347             MACRO_BANNER_SHOW_INFO(parent, _("Error adding POI"));
1348         }
1349
1350         sqlite3_reset(_stmt_insert_poi);
1351
1352         /* We're done. */
1353         break;
1354     }
1355
1356     g_free(poi.label);
1357     g_free(poi.desc);
1358     g_free(dpoi.txt_label);
1359
1360     map_force_redraw();
1361
1362     gtk_widget_hide(dialog);
1363
1364     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1365     return !dpoi.deleted;
1366 }
1367
1368 gboolean
1369 poi_view_dialog(GtkWidget *parent, PoiInfo *poi)
1370 {
1371     GtkTreeIter iter;
1372     static GtkWidget *dialog;
1373     static GtkWidget *table;
1374     static GtkWidget *label;
1375     static GtkWidget *txt_label;
1376     static GtkWidget *txt_lat;
1377     static GtkWidget *txt_lon;
1378     static GtkWidget *cmb_category;
1379     static GtkWidget *txt_desc;
1380     static GtkWidget *btn_delete = NULL;
1381     static GtkWidget *btn_catedit;
1382     static GtkWidget *hbox;
1383     static GtkWidget *txt_scroll;
1384     static GtkTextBuffer *desc_txt;
1385     static GtkTextIter begin, end;
1386     static DeletePOI dpoi = {NULL, NULL, 0};
1387     static PoiCategoryEditInfo pcedit;
1388     printf("%s()\n", __PRETTY_FUNCTION__);
1389
1390     if(dialog == NULL)
1391     {
1392         dialog = gtk_dialog_new_with_buttons(_("Edit POI"),
1393             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
1394             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1395             NULL);
1396
1397         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1398                 btn_delete = gtk_button_new_with_label(_("Delete...")));
1399
1400         gtk_dialog_add_button(GTK_DIALOG(dialog),
1401                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
1402
1403         /* Set the lat/lon strings. */
1404         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1405                 table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
1406
1407         gtk_table_attach(GTK_TABLE(table),
1408                 label = gtk_label_new(_("Lat")),
1409                 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1410         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1411         gtk_table_attach(GTK_TABLE(table),
1412                 txt_lat = gtk_entry_new(),
1413                 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1414
1415         gtk_table_attach(GTK_TABLE(table),
1416                 label = gtk_label_new(_("Lon")),
1417                 2, 3, 0, 1, GTK_FILL, 0, 2, 0);
1418         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1419         gtk_table_attach(GTK_TABLE(table),
1420                 txt_lon = gtk_entry_new(),
1421                 3, 4, 0, 1, GTK_FILL, 0, 2, 0);
1422
1423         gtk_table_attach(GTK_TABLE(table),
1424                 label = gtk_label_new(_("Label")),
1425                 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1426         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1427         gtk_table_attach(GTK_TABLE(table),
1428                 txt_label = gtk_entry_new(),
1429                 1, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1430
1431         gtk_table_attach(GTK_TABLE(table),
1432                 label = gtk_label_new(_("Category")),
1433                 0, 1, 3, 4, GTK_FILL, 0, 2, 0);
1434         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1435         gtk_table_attach(GTK_TABLE(table),
1436                 hbox = gtk_hbox_new(FALSE, 4),
1437                 1, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1438         gtk_box_pack_start(GTK_BOX(hbox),
1439                 cmb_category = poi_create_cat_combo(),
1440                 FALSE, FALSE, 0);
1441
1442         gtk_box_pack_start(GTK_BOX(hbox),
1443                 btn_catedit = gtk_button_new_with_label(
1444                     _("Edit Categories...")),
1445                 FALSE, FALSE, 0);
1446
1447         gtk_table_attach(GTK_TABLE(table),
1448                 label = gtk_label_new(_("Description")),
1449                 0, 1, 5, 6, GTK_FILL, GTK_FILL, 2, 0);
1450         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.0f);
1451
1452         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
1453         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
1454                 GTK_SHADOW_IN);
1455         gtk_table_attach(GTK_TABLE(table),
1456                 txt_scroll,
1457                 1, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1458
1459         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
1460                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1461
1462         txt_desc = gtk_text_view_new ();
1463         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
1464
1465         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
1466         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 550, 120);
1467
1468         desc_txt = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt_desc));
1469
1470         g_signal_connect(G_OBJECT(btn_delete), "clicked",
1471                           G_CALLBACK(poi_delete), &dpoi);
1472
1473         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
1474                 G_CALLBACK(poi_edit_cat), &pcedit);
1475     }
1476
1477     dpoi.dialog = dialog;
1478     dpoi.txt_label = g_strdup(poi->label);
1479     dpoi.id = poi->poi_id;
1480     dpoi.deleted = FALSE;
1481
1482     /* Lat/Lon */
1483     {
1484         gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
1485
1486         lat_format(poi->lat, tmp1);
1487         lon_format(poi->lon, tmp2);
1488
1489         gtk_entry_set_text(GTK_ENTRY(txt_lat), tmp1);
1490         gtk_entry_set_text(GTK_ENTRY(txt_lon), tmp2);
1491     }
1492
1493     /* label */
1494     gtk_entry_set_text(GTK_ENTRY(txt_label), poi->label);
1495
1496     /* poi_desc */
1497     gtk_text_buffer_set_text(desc_txt, poi->desc, -1);
1498
1499     /* Category. */
1500     gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(
1501                     GTK_COMBO_BOX(cmb_category))));
1502     if(poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1503                 GTK_COMBO_BOX(cmb_category))), poi->cat_id, &iter))
1504         gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
1505
1506     /* Connect Signals */
1507     pcedit.dialog = dialog;
1508     pcedit.cmb_category = cmb_category;
1509     pcedit.cat_id = poi->cat_id;
1510
1511     gtk_widget_show_all(dialog);
1512
1513     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1514     {
1515         const gchar *text;
1516         gchar *error_check;
1517
1518         text = gtk_entry_get_text(GTK_ENTRY(txt_lat));
1519         poi->lat = strdmstod(text, &error_check);
1520         if(text == error_check || poi->lat < -90. || poi->lat > 90.) {
1521             popup_error(dialog, _("Invalid Latitude"));
1522             continue;
1523         }
1524
1525         text = gtk_entry_get_text(GTK_ENTRY(txt_lon));
1526         poi->lon = strdmstod(text, &error_check);
1527         if(text == error_check || poi->lon < -180. || poi->lon > 180.) {
1528             popup_error(dialog, _("Invalid Longitude"));
1529             continue;
1530         }
1531
1532         if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
1533         {
1534             if(poi->label)
1535                 g_free(poi->label);
1536             poi->label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
1537         }
1538         else
1539         {
1540             popup_error(dialog, _("Please specify a name."));
1541             continue;
1542         }
1543
1544         if(!gtk_combo_box_get_active_iter(
1545                 GTK_COMBO_BOX(cmb_category), &iter))
1546         {
1547             popup_error(dialog, _("Please specify a category."));
1548             continue;
1549         }
1550
1551         gtk_text_buffer_get_iter_at_offset(desc_txt, &begin,0 );
1552         gtk_text_buffer_get_end_iter (desc_txt, &end);
1553         if(poi->desc)
1554             g_free(poi->desc);
1555         poi->desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
1556
1557         if(poi->clabel)
1558             g_free(poi->clabel);
1559         gtk_tree_model_get(
1560                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
1561                 0, &poi->cat_id,
1562                 1, &poi->clabel,
1563                 -1);
1564
1565         /* edit poi */
1566         if(SQLITE_OK != sqlite3_bind_double(
1567                     _stmt_update_poi, 1, poi->lat) ||
1568            SQLITE_OK != sqlite3_bind_double(
1569                _stmt_update_poi, 2, poi->lon) ||
1570            SQLITE_OK != sqlite3_bind_text(_stmt_update_poi, 3, poi->label,
1571                     -1, SQLITE_STATIC) ||
1572            SQLITE_OK != sqlite3_bind_text(_stmt_update_poi, 4, poi->desc,
1573                -1, SQLITE_STATIC) ||
1574            SQLITE_OK != sqlite3_bind_int(
1575                _stmt_update_poi, 5, poi->cat_id) ||
1576            SQLITE_OK != sqlite3_bind_int(
1577                _stmt_update_poi, 6, poi->poi_id) ||
1578            SQLITE_DONE != sqlite3_step(_stmt_update_poi))
1579         {
1580             MACRO_BANNER_SHOW_INFO(parent, _("Error updating POI"));
1581         }
1582
1583         sqlite3_reset(_stmt_update_poi);
1584
1585         /* We're done. */
1586         break;
1587     }
1588
1589     g_free(dpoi.txt_label);
1590
1591     map_force_redraw();
1592
1593     gtk_widget_hide(dialog); /* Destroying causes a crash.... ??? */
1594
1595     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1596     return !dpoi.deleted;
1597 }
1598
1599 static gint
1600 poi_list_insert(GtkWidget *parent, GList *poi_list, GtkComboBox *cmb_category)
1601 {
1602     gint default_cat_id;
1603     gchar *default_cat_label;
1604     gint num_inserts = 0;
1605     GList *curr;
1606     GtkTreeIter iter;
1607     printf("%s()\n", __PRETTY_FUNCTION__);
1608
1609     /* Get defaults from the given GtkComboBox */
1610     if(!gtk_combo_box_get_active_iter(
1611             GTK_COMBO_BOX(cmb_category), &iter))
1612     {
1613         vprintf("%s(): return 0\n", __PRETTY_FUNCTION__);
1614         return 0;
1615     }
1616     gtk_tree_model_get(
1617             gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
1618             &iter,
1619             0, &default_cat_id,
1620             1, &default_cat_label,
1621             -1);
1622
1623     /* Iterate through the data model and import as desired. */
1624     for(curr = poi_list; curr; )
1625     {
1626         PoiInfo *poi = curr->data;
1627         if(
1628         (    SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 1, poi->lat)
1629           || SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 2, poi->lon)
1630           || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 3, poi->label,
1631              -1, SQLITE_STATIC)
1632           || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 4, poi->desc,
1633              -1, SQLITE_STATIC)
1634           || SQLITE_OK != sqlite3_bind_int(_stmt_insert_poi, 5,
1635               poi->cat_id = default_cat_id)
1636           || SQLITE_DONE != sqlite3_step(_stmt_insert_poi)
1637         ))
1638         {
1639             /* Failure. */
1640             GList *tmp = curr->next;
1641             if(poi->label)
1642                 g_free(poi->label);
1643             if(poi->desc)
1644                 g_free(poi->desc);
1645             g_slice_free(PoiInfo, poi);
1646             poi_list = g_list_delete_link(poi_list, curr);
1647             curr = tmp;
1648         }
1649         else
1650         {
1651             /* Success. */
1652             ++num_inserts;
1653             if(default_cat_label)
1654                 poi->clabel = g_strdup(default_cat_label);
1655             poi->poi_id = sqlite3_last_insert_rowid(_poi_db);
1656             curr = curr->next;
1657         }
1658         sqlite3_reset(_stmt_insert_poi);
1659     }
1660
1661     if(num_inserts)
1662     {
1663         gchar buffer[BUFFER_SIZE];
1664         map_force_redraw();
1665         snprintf(buffer, sizeof(buffer), "%d %s", num_inserts,
1666            _("POIs were added to the POI database.  The following screen will "
1667                "allow you to modify or delete any of the new POIs."));
1668         popup_error(parent, buffer);
1669     }
1670     else
1671     {
1672         popup_error(parent, _("No POIs were found."));
1673     }
1674
1675     if(default_cat_label)
1676         g_free(default_cat_label);
1677
1678     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, num_inserts);
1679     return num_inserts;
1680 }
1681
1682 static void
1683 poi_list_free(GList *poi_list)
1684 {
1685     GList *curr;
1686     printf("%s()\n", __PRETTY_FUNCTION__);
1687
1688     for(curr = poi_list; curr; curr = curr->next)
1689     {
1690         PoiInfo *poi_info = curr->data;
1691         if(poi_info)
1692         {
1693             if(poi_info->label)
1694                 g_free(poi_info->label);
1695             if(poi_info->desc)
1696                 g_free(poi_info->desc);
1697             if(poi_info->clabel)
1698                 g_free(poi_info->clabel);
1699             g_slice_free(PoiInfo, poi_info);
1700         }
1701     }
1702
1703     g_list_free(poi_list);
1704
1705     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1706 }
1707
1708 static void
1709 poi_list_bearing_cell_data_func(
1710         GtkTreeViewColumn *tree_column,
1711         GtkCellRenderer *cell,
1712         GtkTreeModel *tree_model,
1713         GtkTreeIter *iter)
1714 {
1715     gchar buffer[80];
1716     gfloat f;
1717     vprintf("%s()\n", __PRETTY_FUNCTION__);
1718
1719     gtk_tree_model_get(tree_model, iter, POI_BEARING, &f, -1);
1720     snprintf(buffer, sizeof(buffer), "%.1f", f);
1721     g_object_set(cell, "text", buffer, NULL);
1722
1723     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1724 }
1725
1726 static void
1727 poi_list_distance_cell_data_func(
1728         GtkTreeViewColumn *tree_column,
1729         GtkCellRenderer *cell,
1730         GtkTreeModel *tree_model,
1731         GtkTreeIter *iter)
1732 {
1733     gchar buffer[80];
1734     gfloat f;
1735     vprintf("%s()\n", __PRETTY_FUNCTION__);
1736
1737     gtk_tree_model_get(tree_model, iter, POI_DISTANCE, &f, -1);
1738     snprintf(buffer, sizeof(buffer), "%.2f", f);
1739     g_object_set(cell, "text", buffer, NULL);
1740
1741     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1742 }
1743
1744 static gboolean
1745 poi_list_row_selected(GtkCellRendererToggle *renderer,
1746         gchar *path_string, GtkTreeModel *tree_model)
1747 {
1748     GtkTreeIter iter;
1749     vprintf("%s()\n", __PRETTY_FUNCTION__);
1750
1751     if(gtk_tree_model_get_iter_from_string(tree_model, &iter, path_string))
1752     {
1753         gboolean old_value;
1754         gtk_tree_model_get(tree_model, &iter, POI_SELECTED, &old_value, -1);
1755         gtk_list_store_set(GTK_LIST_STORE(tree_model), &iter,
1756                 POI_SELECTED, !old_value,
1757                 -1);
1758     }
1759
1760     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1761     return TRUE;
1762 }
1763
1764 static gboolean
1765 poi_list_set_category(GtkWidget *widget, PoiListInfo *pli)
1766 {
1767     static GtkWidget *dialog = NULL;
1768     static GtkWidget *cmb_category = NULL;
1769     static GtkWidget *btn_catedit = NULL;
1770     static PoiCategoryEditInfo pcedit;
1771     printf("%s()\n", __PRETTY_FUNCTION__);
1772
1773     if(dialog == NULL)
1774     {
1775         GtkWidget *hbox;
1776         GtkWidget *label;
1777
1778         dialog = gtk_dialog_new_with_buttons(_("Set Category..."),
1779                 GTK_WINDOW(pli->dialog2), GTK_DIALOG_MODAL,
1780                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1781                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1782                 NULL);
1783
1784         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1785                 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1786
1787         gtk_box_pack_start(GTK_BOX(hbox),
1788                 label = gtk_label_new(_("Category")),
1789                 FALSE, FALSE, 0);
1790
1791         gtk_box_pack_start(GTK_BOX(hbox),
1792                 cmb_category = poi_create_cat_combo(),
1793                 FALSE, FALSE, 4);
1794
1795         gtk_box_pack_start(GTK_BOX(hbox),
1796                 btn_catedit = gtk_button_new_with_label(
1797                     _("Edit Categories...")),
1798                 FALSE, FALSE, 0);
1799
1800         /* Connect Signals */
1801         pcedit.dialog = dialog;
1802         pcedit.cmb_category = cmb_category;
1803         pcedit.cat_id = -1;
1804         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
1805                 G_CALLBACK(poi_edit_cat), &pcedit);
1806     }
1807
1808     gtk_widget_show_all(dialog);
1809
1810     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1811     {
1812         GtkTreeIter iter;
1813         GtkListStore *store;
1814         gint cat_id;
1815         const gchar *cat_label;
1816
1817         /* Get the text of the chosen category. */
1818         if(!gtk_combo_box_get_active_iter(
1819                 GTK_COMBO_BOX(cmb_category), &iter))
1820         {
1821             popup_error(dialog, _("Please specify a category."));
1822             continue;
1823         }
1824
1825         gtk_tree_model_get(
1826                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
1827                 &iter,
1828                 0, &cat_id,
1829                 1, &cat_label,
1830                 -1);
1831
1832         /* Iterate through the data store and categorize as desired. */
1833         store = GTK_LIST_STORE(gtk_tree_view_get_model(
1834                     GTK_TREE_VIEW(pli->tree_view)));
1835         if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
1836         {
1837             PoiInfo poi;
1838             gboolean selected;
1839
1840             memset(&poi, 0, sizeof(poi));
1841
1842             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1843                     POI_SELECTED, &selected,
1844                     POI_POIID, &(poi.poi_id),
1845                     POI_LAT, &(poi.lat),
1846                     POI_LON, &(poi.lon),
1847                     POI_LABEL, &(poi.label),
1848                     POI_DESC, &(poi.desc),
1849                     -1);
1850
1851             if(selected)
1852             {
1853                 gtk_list_store_set(store, &iter,
1854                     POI_CATID, cat_id,
1855                     POI_CLABEL, cat_label,
1856                     -1);
1857                 /* edit poi */
1858                 if(SQLITE_OK != sqlite3_bind_double(
1859                             _stmt_update_poi, 1, poi.lat) ||
1860                    SQLITE_OK != sqlite3_bind_double(
1861                        _stmt_update_poi, 2, poi.lon) ||
1862                    SQLITE_OK != sqlite3_bind_text(_stmt_update_poi,
1863                        3, poi.label, -1, SQLITE_STATIC) ||
1864                    SQLITE_OK != sqlite3_bind_text(_stmt_update_poi,
1865                        4, poi.desc, -1, SQLITE_STATIC) ||
1866                    SQLITE_OK != sqlite3_bind_int(
1867                        _stmt_update_poi, 5, cat_id) ||
1868                    SQLITE_OK != sqlite3_bind_int(
1869                        _stmt_update_poi, 6, poi.poi_id) ||
1870                    SQLITE_DONE != sqlite3_step(_stmt_update_poi))
1871                 {
1872                     MACRO_BANNER_SHOW_INFO(pli->dialog2,
1873                             _("Error updating POI"));
1874                 }
1875                 sqlite3_reset(_stmt_update_poi);
1876             }
1877         } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
1878
1879         break;
1880     }
1881
1882     map_force_redraw();
1883     gtk_widget_hide(dialog);
1884
1885     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1886     return TRUE;
1887 }
1888
1889 static gboolean
1890 poi_list_select_all(GtkTreeViewColumn *column, PoiListInfo *pli)
1891 {
1892     GtkTreeIter iter;
1893     GtkListStore *store;
1894     printf("%s()\n", __PRETTY_FUNCTION__);
1895
1896     /* Iterate through the data store and select as desired. */
1897     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1898                 GTK_TREE_VIEW(pli->tree_view)));
1899     if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
1900     {
1901         gtk_list_store_set(store, &iter,
1902             POI_SELECTED, pli->select_all,
1903             -1);
1904     } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
1905
1906     pli->select_all = !pli->select_all;
1907
1908     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1909     return TRUE;
1910 }
1911
1912 static gboolean
1913 poi_list_view(GtkWidget *widget, PoiListInfo *pli)
1914 {
1915     GtkTreeIter iter;
1916     GtkTreeSelection *selection;
1917     GtkListStore *store;
1918     printf("%s()\n", __PRETTY_FUNCTION__);
1919
1920     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pli->tree_view));
1921     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1922                 GTK_TREE_VIEW(pli->tree_view)));
1923
1924     /* Iterate through the data store and import as desired. */
1925     if(gtk_tree_selection_get_selected(selection, NULL, &iter))
1926     {
1927         PoiInfo poi;
1928         memset(&poi, 0, sizeof(poi));
1929
1930         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1931                 POI_POIID, &(poi.poi_id),
1932                 POI_CATID, &(poi.cat_id),
1933                 POI_LAT, &(poi.lat),
1934                 POI_LON, &(poi.lon),
1935                 POI_LABEL, &(poi.label),
1936                 POI_DESC, &(poi.desc),
1937                 POI_CLABEL, &(poi.clabel),
1938                 -1);
1939
1940         if(poi_view_dialog(pli->dialog, &poi))
1941         {
1942             gtk_list_store_set(store, &iter,
1943                     POI_POIID, poi.poi_id,
1944                     POI_CATID, poi.cat_id,
1945                     POI_LAT, poi.lat,
1946                     POI_LON, poi.lon,
1947                     POI_LABEL, poi.label,
1948                     POI_DESC, poi.desc,
1949                     POI_CLABEL, poi.clabel,
1950                     -1);
1951         }
1952         else
1953         {
1954             /* POI was deleted. */
1955             gtk_list_store_remove(store, &iter);
1956         }
1957     }
1958
1959     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1960     return TRUE;
1961 }
1962
1963 static void
1964 poi_list_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
1965         GtkTreeViewColumn *column, PoiListInfo *pli)
1966 {
1967     printf("%s()\n", __PRETTY_FUNCTION__);
1968
1969     if(column != pli->select_column)
1970         poi_list_view(GTK_WIDGET(tree_view), pli);
1971
1972     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1973 }
1974
1975 static gboolean
1976 poi_list_goto(GtkWidget *widget, PoiListInfo *pli)
1977 {
1978     GtkTreeIter iter;
1979     GtkTreeSelection *selection;
1980     GtkListStore *store;
1981     printf("%s()\n", __PRETTY_FUNCTION__);
1982
1983     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pli->tree_view));
1984     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1985                 GTK_TREE_VIEW(pli->tree_view)));
1986
1987     /* Iterate through the data store and import as desired. */
1988     if(gtk_tree_selection_get_selected(selection, NULL, &iter))
1989     {
1990         gdouble lat, lon;
1991         Point unit;
1992
1993         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1994                 POI_LAT, &lat,
1995                 POI_LON, &lon,
1996                 -1);
1997
1998         latlon2unit(lat, lon, unit.unitx, unit.unity);
1999
2000         if(_center_mode > 0)
2001             gtk_check_menu_item_set_active(
2002                     GTK_CHECK_MENU_ITEM(_menu_view_ac_none_item), TRUE);
2003
2004         map_center_unit(unit);
2005     }
2006
2007     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2008     return TRUE;
2009 }
2010
2011 static gboolean
2012 poi_list_delete(GtkWidget *widget, PoiListInfo *pli)
2013 {
2014     GtkWidget *confirm;
2015     printf("%s()\n", __PRETTY_FUNCTION__);
2016
2017     confirm = hildon_note_new_confirmation(
2018             GTK_WINDOW(pli->dialog2), _("Delete selected POI?"));
2019
2020     if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2021     {
2022         GtkTreeIter iter;
2023         GtkListStore *store;
2024         gboolean already_next;
2025         gboolean must_iterate;;
2026
2027         /* Iterate through the data store and import as desired. */
2028         store = GTK_LIST_STORE(gtk_tree_view_get_model(
2029                     GTK_TREE_VIEW(pli->tree_view)));
2030         if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
2031         {
2032             gboolean selected;
2033             must_iterate = TRUE;
2034             already_next = FALSE;
2035             gint poi_id;
2036             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
2037                 POI_SELECTED, &selected,
2038                 POI_POIID, &poi_id,
2039                 -1);
2040             if(selected)
2041             {
2042                 /* Delete POI. */
2043                 if(SQLITE_OK != sqlite3_bind_int(_stmt_delete_poi, 1, poi_id)
2044                 || SQLITE_DONE != sqlite3_step(_stmt_delete_poi))
2045                 {
2046                     MACRO_BANNER_SHOW_INFO(pli->dialog2,
2047                             _("Error deleting POI"));
2048                 }
2049                 else
2050                 {
2051                     already_next = gtk_list_store_remove(store, &iter);
2052                     must_iterate = FALSE;
2053                 }
2054                 sqlite3_reset(_stmt_delete_poi);
2055             }
2056         } while(already_next || (must_iterate
2057                 && gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)));
2058     }
2059
2060     map_force_redraw();
2061
2062     gtk_widget_destroy(confirm);
2063
2064     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2065     return TRUE;
2066 }
2067
2068 static gboolean
2069 poi_list_export_gpx(GtkWidget *widget, PoiListInfo *pli)
2070 {
2071     GnomeVFSHandle *handle;
2072     printf("%s()\n", __PRETTY_FUNCTION__);
2073
2074     if(display_open_file(pli->dialog2, NULL, &handle, NULL, NULL, NULL,
2075                     GTK_FILE_CHOOSER_ACTION_SAVE))
2076     {
2077         gint num_exported = gpx_poi_write(
2078                gtk_tree_view_get_model(GTK_TREE_VIEW(pli->tree_view)), handle);
2079         if(num_exported >= 0)
2080         {
2081             gchar buffer[80];
2082             snprintf(buffer, sizeof(buffer), "%d %s\n", num_exported,
2083                     _("POIs Exported"));
2084             MACRO_BANNER_SHOW_INFO(pli->dialog2, buffer);
2085         }
2086         else
2087             popup_error(pli->dialog2, _("Error writing GPX file."));
2088         gnome_vfs_close(handle);
2089     }
2090
2091     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2092     return TRUE;
2093 }
2094
2095 static gboolean
2096 poi_list_manage_checks(GtkWidget *widget, PoiListInfo *pli)
2097 {
2098     GtkWidget *btn_category;
2099     GtkWidget *btn_delete;
2100     GtkWidget *btn_export_gpx;
2101
2102     printf("%s()\n", __PRETTY_FUNCTION__);
2103
2104     pli->dialog2 = gtk_dialog_new_with_buttons(_("Checked POI Actions..."),
2105             GTK_WINDOW(pli->dialog), GTK_DIALOG_MODAL,
2106             NULL);
2107
2108     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2109             gtk_label_new(_("Select an operation to perform\n"
2110                             "on the POIs that you checked\n"
2111                             "in the POI list.")),
2112                 FALSE, FALSE, 4);
2113
2114     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2115             btn_category = gtk_button_new_with_label(_("Set Category...")),
2116                 FALSE, FALSE, 4);
2117
2118     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2119             btn_delete = gtk_button_new_with_label(_("Delete...")),
2120                 FALSE, FALSE, 4);
2121
2122     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2123             btn_export_gpx = gtk_button_new_with_label(
2124                 _("Export to GPX...")),
2125                 FALSE, FALSE, 4);
2126
2127     gtk_dialog_add_button(GTK_DIALOG(pli->dialog2),
2128             GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT);
2129
2130     g_signal_connect(G_OBJECT(btn_category), "clicked",
2131             G_CALLBACK(poi_list_set_category), pli);
2132
2133     g_signal_connect(G_OBJECT(btn_delete), "clicked",
2134             G_CALLBACK(poi_list_delete), pli);
2135
2136     g_signal_connect(G_OBJECT(btn_export_gpx), "clicked",
2137             G_CALLBACK(poi_list_export_gpx), pli);
2138
2139     gtk_widget_show_all(pli->dialog2);
2140
2141     gtk_dialog_run(GTK_DIALOG(pli->dialog2));
2142
2143     gtk_widget_destroy(pli->dialog2);
2144     pli->dialog2 = NULL;
2145
2146     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2147     return TRUE;
2148 }
2149
2150 static gboolean
2151 poi_list_dialog(GtkWidget *parent, gint unitx, gint unity, GList *poi_list)
2152 {
2153     static PoiListInfo pli = { NULL, NULL };
2154     static GtkWidget *scroller;
2155     static GtkWidget *btn_goto;
2156     static GtkWidget *btn_edit;
2157     static GtkWidget *btn_manage_checks;
2158     static GtkListStore *store;
2159     GtkTreeIter iter;
2160     GList *curr;
2161     gdouble src_lat, src_lon;
2162     printf("%s()\n", __PRETTY_FUNCTION__);
2163
2164     if(pli.dialog == NULL)
2165     {
2166         GtkCellRenderer *renderer;
2167         GtkTreeViewColumn *column;
2168
2169         pli.dialog = gtk_dialog_new_with_buttons(_("POI List"),
2170             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
2171                 NULL);
2172
2173         store = gtk_list_store_new(POI_NUM_COLUMNS,
2174                                    G_TYPE_BOOLEAN,/* Selected */
2175                                    G_TYPE_INT,    /* POI ID */
2176                                    G_TYPE_INT,    /* Category ID */
2177                                    G_TYPE_DOUBLE, /* Latitude */
2178                                    G_TYPE_DOUBLE, /* Longitude */
2179                                    G_TYPE_STRING, /* Lat/Lon */
2180                                    G_TYPE_FLOAT,  /* Bearing */
2181                                    G_TYPE_FLOAT,  /* Distance */
2182                                    G_TYPE_STRING, /* POI Label */
2183                                    G_TYPE_STRING, /* POI Desc. */
2184                                    G_TYPE_STRING);/* Category Label */
2185
2186         /* Set up the tree view. */
2187         pli.tree_view = gtk_tree_view_new();
2188         g_object_set(G_OBJECT(pli.tree_view),
2189                 "allow-checkbox-mode", FALSE, NULL);
2190
2191         gtk_tree_selection_set_mode(
2192                 gtk_tree_view_get_selection(GTK_TREE_VIEW(pli.tree_view)),
2193                 GTK_SELECTION_SINGLE);
2194         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pli.tree_view), TRUE);
2195
2196         renderer = gtk_cell_renderer_toggle_new();
2197         gtk_cell_renderer_toggle_set_active(GTK_CELL_RENDERER_TOGGLE(renderer),
2198                 TRUE);
2199         g_signal_connect(G_OBJECT(renderer), "toggled",
2200                 G_CALLBACK(poi_list_row_selected), store);
2201         pli.select_column = gtk_tree_view_column_new_with_attributes(
2202                 "*", renderer, "active", POI_SELECTED, NULL);
2203         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view),
2204                 pli.select_column);
2205         gtk_tree_view_column_set_clickable(pli.select_column, TRUE);
2206         g_signal_connect(G_OBJECT(pli.select_column), "clicked",
2207                 G_CALLBACK(poi_list_select_all), &pli);
2208
2209         renderer = gtk_cell_renderer_combo_new();
2210         column = gtk_tree_view_column_new_with_attributes(
2211                 _("Category"), renderer, "text", POI_CLABEL, NULL);
2212         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_GROW_ONLY);
2213         gtk_tree_view_column_set_sort_column_id(column, POI_CLABEL);
2214         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2215
2216         renderer = gtk_cell_renderer_text_new();
2217         g_object_set(renderer, "xalign", 1.f, NULL);
2218         column = gtk_tree_view_column_new_with_attributes(
2219                 _("Dist."), renderer, "text", POI_DISTANCE, NULL);
2220         gtk_tree_view_column_set_cell_data_func(column, renderer,
2221                 (GtkTreeCellDataFunc)poi_list_distance_cell_data_func,
2222                 NULL, NULL);
2223         gtk_tree_view_column_set_sort_column_id(column, POI_DISTANCE);
2224         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2225
2226         renderer = gtk_cell_renderer_text_new();
2227         g_object_set(renderer, "xalign", 1.f, NULL);
2228         column = gtk_tree_view_column_new_with_attributes(
2229                 _("Bear."), renderer, "text", POI_BEARING, NULL);
2230         gtk_tree_view_column_set_cell_data_func(column, renderer,
2231                 (GtkTreeCellDataFunc)poi_list_bearing_cell_data_func,
2232                 NULL, NULL);
2233         gtk_tree_view_column_set_sort_column_id(column, POI_BEARING);
2234         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2235
2236         renderer = gtk_cell_renderer_text_new();
2237         column = gtk_tree_view_column_new_with_attributes(
2238                 _("Label"), renderer, "text", POI_LABEL, NULL);
2239         gtk_tree_view_column_set_sort_column_id(column, POI_LABEL);
2240         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2241
2242         g_signal_connect(G_OBJECT(pli.tree_view), "row-activated",
2243                 G_CALLBACK(poi_list_row_activated), &pli);
2244
2245         gtk_tree_view_set_model(GTK_TREE_VIEW(pli.tree_view),
2246                 GTK_TREE_MODEL(store));
2247         g_object_unref(G_OBJECT(store));
2248
2249         /* Enable the help button. */
2250 #ifndef LEGACY
2251         hildon_help_dialog_help_enable(
2252 #else
2253         ossohelp_dialog_help_enable(
2254 #endif
2255                 GTK_DIALOG(pli.dialog), HELP_ID_POILIST, _osso);
2256
2257         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2258                 btn_goto = gtk_button_new_with_label(_("Go to")));
2259
2260         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2261                 btn_edit = gtk_button_new_with_label(_("Edit...")));
2262
2263         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2264                 btn_manage_checks = gtk_button_new_with_label(
2265                     _("Checked POI Actions...")));
2266
2267         gtk_dialog_add_button(GTK_DIALOG(pli.dialog),
2268                 GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT);
2269
2270         gtk_window_set_default_size(GTK_WINDOW(pli.dialog), 500, 400);
2271
2272         scroller = gtk_scrolled_window_new (NULL, NULL);
2273         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroller),
2274                 GTK_SHADOW_ETCHED_IN);
2275         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
2276                 GTK_POLICY_NEVER,
2277                 GTK_POLICY_AUTOMATIC);
2278         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli.dialog)->vbox),
2279                 scroller, TRUE, TRUE, 0);
2280
2281         gtk_container_add(GTK_CONTAINER(scroller), pli.tree_view);
2282
2283         g_signal_connect(G_OBJECT(btn_goto), "clicked",
2284                 G_CALLBACK(poi_list_goto), &pli);
2285
2286         g_signal_connect(G_OBJECT(btn_edit), "clicked",
2287                 G_CALLBACK(poi_list_view), &pli);
2288
2289         g_signal_connect(G_OBJECT(btn_manage_checks), "clicked",
2290                 G_CALLBACK(poi_list_manage_checks), &pli);
2291     }
2292
2293     /* Initialize the tree store. */
2294
2295     gtk_list_store_clear(store);
2296     pli.select_all = FALSE;
2297
2298     unit2latlon(unitx, unity, src_lat, src_lon);
2299
2300     for(curr = poi_list; curr; curr = curr->next)
2301     {
2302         PoiInfo *poi_info = curr->data;
2303         gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
2304
2305         printf("poi: (%f, %f, %s, %s)\n",
2306                 poi_info->lat, poi_info->lon,
2307                 poi_info->label, poi_info->desc);
2308
2309         lat_format(poi_info->lat, tmp1);
2310         lon_format(poi_info->lon, tmp2);
2311
2312         gtk_list_store_append(store, &iter);
2313         gtk_list_store_set(store, &iter,
2314                 POI_SELECTED, TRUE,
2315                 POI_POIID, poi_info->poi_id,
2316                 POI_LAT, poi_info->lat,
2317                 POI_LON, poi_info->lon,
2318                 POI_BEARING, calculate_bearing(src_lat, src_lon,
2319                     poi_info->lat, poi_info->lon),
2320                 POI_DISTANCE, calculate_distance(src_lat,src_lon,
2321                     poi_info->lat, poi_info->lon) * UNITS_CONVERT[_units],
2322                 POI_LABEL, poi_info->label,
2323                 POI_DESC, poi_info->desc,
2324                 POI_CATID, poi_info->cat_id,
2325                 POI_CLABEL, poi_info->clabel,
2326                 -1);
2327     }
2328
2329     gtk_widget_show_all(pli.dialog);
2330
2331     GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(pli.dialog));
2332
2333     map_force_redraw();
2334
2335     gtk_widget_hide(pli.dialog);
2336
2337     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2338     return TRUE;
2339 }
2340
2341 gboolean
2342 poi_import_dialog(gint unitx, gint unity)
2343 {
2344     GtkWidget *dialog = NULL;
2345     gboolean success = FALSE;
2346     printf("%s()\n", __PRETTY_FUNCTION__);
2347
2348     dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(_window),
2349             GTK_FILE_CHOOSER_ACTION_OPEN);
2350
2351     gtk_widget_show_all(dialog);
2352
2353     while(!success && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2354     {
2355         gchar *file_uri_str = NULL;
2356         gchar *bytes = NULL;
2357         gint size;
2358         GnomeVFSResult vfs_result;
2359         GList *poi_list = NULL;
2360
2361         file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2362
2363         /* Parse the given file as GPX. */
2364         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2365                         file_uri_str, &size, &bytes)))
2366         {
2367             popup_error(dialog, gnome_vfs_result_to_string(vfs_result));
2368         }
2369         else if(gpx_poi_parse(bytes, size, &poi_list))
2370         {
2371             static GtkWidget *cat_dialog = NULL;
2372             static GtkWidget *cmb_category = NULL;
2373             static GtkWidget *btn_catedit = NULL;
2374             static PoiCategoryEditInfo pcedit;
2375
2376             if(!cat_dialog)
2377             {
2378                 GtkWidget *hbox;
2379                 GtkWidget *label;
2380                 cat_dialog = gtk_dialog_new_with_buttons(_("Default Category"),
2381                         GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
2382                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2383                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2384                         NULL);
2385
2386                 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cat_dialog)->vbox),
2387                         hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2388
2389                 gtk_box_pack_start(GTK_BOX(hbox),
2390                         label = gtk_label_new(_("Category")),
2391                         FALSE, FALSE, 0);
2392
2393                 gtk_box_pack_start(GTK_BOX(hbox),
2394                         cmb_category = poi_create_cat_combo(),
2395                         FALSE, FALSE, 4);
2396
2397                 gtk_box_pack_start(GTK_BOX(hbox),
2398                         btn_catedit = gtk_button_new_with_label(
2399                             _("Edit Categories...")),
2400                         FALSE, FALSE, 0);
2401
2402                 /* Connect Signals */
2403                 pcedit.dialog = dialog;
2404                 pcedit.cmb_category = cmb_category;
2405                 pcedit.cat_id = -1;
2406                 g_signal_connect(G_OBJECT(btn_catedit), "clicked",
2407                         G_CALLBACK(poi_edit_cat), &pcedit);
2408             }
2409
2410             gtk_widget_show_all(cat_dialog);
2411
2412             while(GTK_RESPONSE_ACCEPT ==gtk_dialog_run(GTK_DIALOG(cat_dialog)))
2413             {
2414                 if(gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_category)) == -1)
2415                 {
2416                     popup_error(dialog,
2417                             _("Please specify a default category."));
2418                     continue;
2419                 }
2420
2421                 /* Insert the POIs into the database. */
2422                 gint num_inserts = poi_list_insert(dialog,
2423                         poi_list, GTK_COMBO_BOX(cmb_category));
2424
2425                 if(num_inserts)
2426                 {
2427                     /* Hide the dialogs. */
2428                     gtk_widget_hide(cat_dialog);
2429
2430                     /* Create a new dialog with the results. */
2431                     poi_list_dialog(dialog, unitx, unity, poi_list);
2432                     success = TRUE;
2433                 }
2434                 break;
2435             }
2436
2437             gtk_widget_hide(cat_dialog);
2438
2439             poi_list_free(poi_list);
2440         }
2441         else
2442             popup_error(dialog, _("Error parsing GPX file."));
2443
2444         g_free(file_uri_str);
2445         g_free(bytes);
2446     }
2447
2448     /* Hide the dialog. */
2449     gtk_widget_destroy(dialog);
2450
2451     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2452     return success;
2453 }
2454
2455 static gboolean
2456 poi_download_cat_selected(GtkComboBox *cmb_category, GtkEntry *txt_query)
2457 {
2458     GtkTreeIter iter;
2459     printf("%s()\n", __PRETTY_FUNCTION__);
2460
2461     if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cmb_category), &iter))
2462     {
2463         gchar buffer[BUFFER_SIZE];
2464         GtkWidget *confirm = NULL;
2465         gchar *category = NULL;
2466
2467         gtk_tree_model_get(
2468                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
2469                 1, &category,
2470                 -1);
2471
2472         if(*gtk_entry_get_text(txt_query))
2473         {
2474             snprintf(buffer, sizeof(buffer), "%s\n  %s",
2475                     _("Overwrite query with the following text?"), category);
2476             confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),buffer);
2477
2478         }
2479
2480         if(confirm == NULL
2481                 || GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2482             gtk_entry_set_text(txt_query, category);
2483
2484         if(confirm)
2485             gtk_widget_destroy(confirm);
2486     }
2487
2488     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2489     return TRUE;
2490 }
2491
2492
2493 static gboolean
2494 origin_type_selected(GtkWidget *toggle, OriginToggleInfo *oti)
2495 {
2496     printf("%s()\n", __PRETTY_FUNCTION__);
2497
2498     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
2499         gtk_widget_set_sensitive(oti->txt_origin, toggle == oti->rad_use_text);
2500
2501     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2502     return TRUE;
2503 }
2504
2505 gboolean
2506 poi_download_dialog(gint unitx, gint unity)
2507 {
2508     static GtkWidget *dialog = NULL;
2509     static GtkWidget *hbox = NULL;
2510     static GtkWidget *table = NULL;
2511     static GtkWidget *table2 = NULL;
2512     static GtkWidget *label = NULL;
2513     static GtkWidget *num_page = NULL;
2514     static GtkWidget *txt_source_url = NULL;
2515     static OriginToggleInfo oti;
2516     static GtkWidget *cmb_category;
2517     printf("%s()\n", __PRETTY_FUNCTION__);
2518
2519     conic_recommend_connected();
2520
2521     if(!dialog)
2522     {
2523         GtkEntryCompletion *origin_comp;
2524
2525         dialog = gtk_dialog_new_with_buttons(_("Download POIs"),
2526                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2527                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2528                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2529                 NULL);
2530
2531         /* Enable the help button. */
2532 #ifndef LEGACY
2533         hildon_help_dialog_help_enable(
2534 #else
2535         ossohelp_dialog_help_enable(
2536 #endif
2537                 GTK_DIALOG(dialog), HELP_ID_DOWNPOI, _osso);
2538
2539         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2540                 table = gtk_table_new(4, 4, FALSE), TRUE, TRUE, 0);
2541
2542         /* Source URL. */
2543         gtk_table_attach(GTK_TABLE(table),
2544                 hbox = gtk_hbox_new(FALSE, 4),
2545                 0, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2546         gtk_box_pack_start(GTK_BOX(hbox),
2547                 label = gtk_label_new(_("Source URL")), FALSE, TRUE, 4);
2548         gtk_box_pack_start(GTK_BOX(hbox),
2549                 txt_source_url = gtk_entry_new(), TRUE, TRUE, 4);
2550
2551         /* Auto. */
2552         gtk_table_attach(GTK_TABLE(table),
2553                 oti.rad_use_gps = gtk_radio_button_new_with_label(NULL,
2554                     _("Use GPS Location")),
2555                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2556
2557         /* Use End of Route. */
2558         gtk_table_attach(GTK_TABLE(table),
2559                oti.rad_use_route = gtk_radio_button_new_with_label_from_widget(
2560                    GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")),
2561                0, 1, 2, 3, GTK_FILL, 0, 2, 4);
2562
2563
2564         gtk_table_attach(GTK_TABLE(table),
2565                 gtk_vseparator_new(),
2566                 1, 2, 1, 3, GTK_FILL, GTK_FILL, 2,4);
2567
2568         /* Category. */
2569         gtk_table_attach(GTK_TABLE(table),
2570                 label = gtk_label_new(_("Category")),
2571                 2, 3, 1, 2, GTK_FILL, 0, 2, 4);
2572         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2573         gtk_table_attach(GTK_TABLE(table),
2574                 cmb_category = poi_create_cat_combo(),
2575                 3, 4, 1, 2, GTK_FILL, 0, 2, 4);
2576
2577         /* Page. */
2578         gtk_table_attach(GTK_TABLE(table),
2579                 label = gtk_label_new(_("Page")),
2580                 2, 3, 2, 3, GTK_FILL, 0, 2, 4);
2581         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2582         gtk_table_attach(GTK_TABLE(table),
2583                 num_page = hildon_number_editor_new(1, 999),
2584                 3, 4, 2, 3, GTK_FILL, 0, 2, 4);
2585
2586
2587         /* Another table for the Origin and Query. */
2588         gtk_table_attach(GTK_TABLE(table),
2589                 table2 = gtk_table_new(2, 2, FALSE),
2590                 0, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2591
2592         /* Origin. */
2593         gtk_table_attach(GTK_TABLE(table2),
2594                 oti.rad_use_text = gtk_radio_button_new_with_label_from_widget(
2595                     GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")),
2596                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2597         gtk_table_attach(GTK_TABLE(table2),
2598                 oti.txt_origin = gtk_entry_new(),
2599                 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2600         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_origin), 25);
2601 #ifndef LEGACY
2602         g_object_set(G_OBJECT(oti.txt_origin), "hildon-input-mode",
2603                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2604 #else
2605         g_object_set(G_OBJECT(oti.txt_origin), HILDON_AUTOCAP, FALSE, NULL);
2606 #endif
2607
2608         /* Query. */
2609         gtk_table_attach(GTK_TABLE(table2),
2610                 label = gtk_label_new(_("Query")),
2611                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2612         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2613         gtk_table_attach(GTK_TABLE(table2),
2614                 oti.txt_query = gtk_entry_new(),
2615                 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2616         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_query), 25);
2617 #ifndef LEGACY
2618         g_object_set(G_OBJECT(oti.txt_query), "hildon-input-mode",
2619                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2620 #else
2621         g_object_set(G_OBJECT(oti.txt_query), HILDON_AUTOCAP, FALSE, NULL);
2622 #endif
2623
2624         /* Set up auto-completion. */
2625         origin_comp = gtk_entry_completion_new();
2626         gtk_entry_completion_set_model(origin_comp,GTK_TREE_MODEL(_loc_model));
2627         gtk_entry_completion_set_text_column(origin_comp, 0);
2628         gtk_entry_set_completion(GTK_ENTRY(oti.txt_origin), origin_comp);
2629
2630         g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled",
2631                           G_CALLBACK(origin_type_selected), &oti);
2632         g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled",
2633                           G_CALLBACK(origin_type_selected), &oti);
2634         g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled",
2635                           G_CALLBACK(origin_type_selected), &oti);
2636
2637         g_signal_connect(G_OBJECT(cmb_category), "changed",
2638                 G_CALLBACK(poi_download_cat_selected), oti.txt_query);
2639     }
2640
2641     /* Initialize fields. */
2642
2643     hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_page), 1);
2644
2645     gtk_entry_set_text(GTK_ENTRY(txt_source_url), _poi_dl_url);
2646     if(unity != 0)
2647     {
2648         gchar buffer[80];
2649         gchar strlat[32];
2650         gchar strlon[32];
2651         gdouble lat, lon;
2652
2653         unit2latlon(unitx, unity, lat, lon);
2654
2655         g_ascii_formatd(strlat, 32, "%.06f", lat);
2656         g_ascii_formatd(strlon, 32, "%.06f", lon);
2657         snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
2658
2659         gtk_entry_set_text(GTK_ENTRY(oti.txt_origin), buffer);
2660         gtk_toggle_button_set_active(
2661                 GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2662     }
2663     /* Else use "End of Route" by default if they have a route. */
2664     else if(_route.head != _route.tail)
2665     {
2666         /* There is no route, so make it the default. */
2667         gtk_widget_set_sensitive(oti.rad_use_route, TRUE);
2668         gtk_toggle_button_set_active(
2669                 GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
2670         gtk_widget_grab_focus(oti.rad_use_route);
2671     }
2672     /* Else use "GPS Location" if they have GPS enabled. */
2673     else
2674     {
2675         /* There is no route, so desensitize "Use End of Route." */
2676         gtk_widget_set_sensitive(oti.rad_use_route, FALSE);
2677         if(_enable_gps)
2678         {
2679             gtk_toggle_button_set_active(
2680                     GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
2681             gtk_widget_grab_focus(oti.rad_use_gps);
2682         }
2683         /* Else use text. */
2684         else
2685         {
2686             gtk_toggle_button_set_active(
2687                     GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2688             gtk_widget_grab_focus(oti.txt_origin);
2689         }
2690     }
2691
2692     gtk_widget_show_all(dialog);
2693
2694     while(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
2695     {
2696         gchar origin_buffer[BUFFER_SIZE];
2697         const gchar *source_url, *origin, *query;
2698         gchar *file_uri_str = NULL;
2699         gchar *bytes = NULL;
2700         gint size;
2701         GnomeVFSResult vfs_result;
2702         GList *poi_list = NULL;
2703
2704         source_url = gtk_entry_get_text(GTK_ENTRY(txt_source_url));
2705         if(!strlen(source_url))
2706         {
2707             popup_error(dialog, _("Please specify a source URL."));
2708             continue;
2709         }
2710         else
2711         {
2712             g_free(_poi_dl_url);
2713             _poi_dl_url = g_strdup(source_url);
2714         }
2715
2716         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)))
2717         {
2718             gchar strlat[32];
2719             gchar strlon[32];
2720             latlon2unit(_gps.lat, _gps.lon, unitx, unity);
2721             g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
2722             g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
2723             snprintf(origin_buffer, sizeof(origin_buffer),
2724                     "%s, %s", strlat, strlon);
2725             origin = origin_buffer;
2726         }
2727         else if(gtk_toggle_button_get_active(
2728                     GTK_TOGGLE_BUTTON(oti.rad_use_route)))
2729         {
2730             gchar strlat[32];
2731             gchar strlon[32];
2732             Point *p;
2733             gdouble lat, lon;
2734
2735             /* Use last non-zero route point. */
2736             for(p = _route.tail; !p->unity; p--) { }
2737
2738             unitx = p->unitx;
2739             unity = p->unity;
2740             unit2latlon(p->unitx, p->unity, lat, lon);
2741             g_ascii_formatd(strlat, 32, "%.06f", lat);
2742             g_ascii_formatd(strlon, 32, "%.06f", lon);
2743             snprintf(origin_buffer, sizeof(origin_buffer),
2744                     "%s, %s", strlat, strlon);
2745             origin = origin_buffer;
2746         }
2747         else
2748         {
2749             Point porig;
2750             origin = gtk_entry_get_text(GTK_ENTRY(oti.txt_origin));
2751             if(*origin)
2752             {
2753                 porig = locate_address(dialog, origin);
2754                 if(!porig.unity)
2755                     continue;
2756             }
2757         }
2758
2759         if(!*origin)
2760         {
2761             popup_error(dialog, _("Please specify an origin."));
2762             continue;
2763         }
2764
2765         if(gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_category)) == -1)
2766         {
2767             popup_error(dialog, _("Please specify a default category."));
2768             continue;
2769         }
2770
2771         query = gtk_entry_get_text(GTK_ENTRY(oti.txt_query));
2772         if(!strlen(query))
2773         {
2774             popup_error(dialog, _("Please specify a query."));
2775             continue;
2776         }
2777
2778         /* Construct the URL. */
2779         {
2780             gchar *origin_escaped;
2781             gchar *query_escaped;
2782
2783             origin_escaped = gnome_vfs_escape_string(origin);
2784             query_escaped = gnome_vfs_escape_string(query);
2785             file_uri_str = g_strdup_printf(
2786                     source_url, origin_escaped, query_escaped,
2787                     hildon_number_editor_get_value(
2788                         HILDON_NUMBER_EDITOR(num_page)));
2789             g_free(origin_escaped);
2790             g_free(query_escaped);
2791         }
2792
2793         /* Parse the given file as GPX. */
2794         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2795                         file_uri_str, &size, &bytes)))
2796         {
2797             popup_error(dialog, gnome_vfs_result_to_string(vfs_result));
2798         }
2799         else if(strncmp(bytes, "<?xml", strlen("<?xml")))
2800         {
2801             /* Not an XML document - must be bad locations. */
2802             popup_error(dialog, _("Invalid origin or query."));
2803             printf("bytes: %s\n", bytes);
2804         }
2805         else if(gpx_poi_parse(bytes, size, &poi_list))
2806         {
2807             /* Insert the POIs into the database. */
2808             gint num_inserts = poi_list_insert(dialog, poi_list,
2809                     GTK_COMBO_BOX(cmb_category));
2810
2811             if(num_inserts)
2812             {
2813                 /* Create a new dialog with the results. */
2814                 poi_list_dialog(dialog, unitx, unity, poi_list);
2815             }
2816
2817             poi_list_free(poi_list);
2818         }
2819         else
2820             popup_error(dialog, _("Error parsing GPX file."));
2821
2822         g_free(file_uri_str);
2823         g_free(bytes);
2824
2825         /* Increment the page number for them. */
2826         hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_page),
2827             hildon_number_editor_get_value(HILDON_NUMBER_EDITOR(num_page)) +1);
2828     }
2829
2830     /* Hide the dialog. */
2831     gtk_widget_hide(dialog);
2832
2833     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2834     return TRUE;
2835 }
2836
2837 gboolean
2838 poi_browse_dialog(gint unitx, gint unity)
2839 {
2840     static GtkWidget *dialog = NULL;
2841     static GtkWidget *table = NULL;
2842     static GtkWidget *table2 = NULL;
2843     static GtkWidget *label = NULL;
2844     static GtkWidget *cmb_category = NULL;
2845     static OriginToggleInfo oti;
2846     printf("%s()\n", __PRETTY_FUNCTION__);
2847
2848     if(!dialog)
2849     {
2850         GtkEntryCompletion *origin_comp;
2851
2852         dialog = gtk_dialog_new_with_buttons(_("Browse POIs"),
2853                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2854                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2855                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2856                 NULL);
2857
2858         /* Enable the help button. */
2859 #ifndef LEGACY
2860         hildon_help_dialog_help_enable(
2861 #else
2862         ossohelp_dialog_help_enable(
2863 #endif
2864                 GTK_DIALOG(dialog), HELP_ID_BROWSEPOI, _osso);
2865
2866         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2867                 table = gtk_table_new(3, 4, FALSE), TRUE, TRUE, 0);
2868
2869         /* Auto. */
2870         gtk_table_attach(GTK_TABLE(table),
2871                 oti.rad_use_gps = gtk_radio_button_new_with_label(NULL,
2872                     _("Use GPS Location")),
2873                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2874
2875         /* Use End of Route. */
2876         gtk_table_attach(GTK_TABLE(table),
2877                oti.rad_use_route = gtk_radio_button_new_with_label_from_widget(
2878                    GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")),
2879                0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2880
2881         gtk_table_attach(GTK_TABLE(table),
2882                 gtk_vseparator_new(),
2883                 1, 2, 0, 2, GTK_FILL, GTK_FILL, 2, 4);
2884
2885         /* Category. */
2886         gtk_table_attach(GTK_TABLE(table),
2887                 label = gtk_label_new(_("Category")),
2888                 2, 3, 0, 1, GTK_FILL, 0, 2, 4);
2889         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2890         gtk_table_attach(GTK_TABLE(table),
2891                 cmb_category = poi_create_cat_combo(),
2892                 3, 4, 0, 1, GTK_FILL, 0, 2, 4);
2893         /* Add an extra, "<any>" category. */
2894         {
2895             GtkTreeIter iter;
2896             GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(
2897                         GTK_COMBO_BOX(cmb_category)));
2898             gtk_list_store_prepend(store, &iter);
2899             gtk_list_store_set(store, &iter, 0, -1, 1, "<any>", -1);
2900             gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
2901         }
2902
2903
2904         /* Another table for the Origin and Query. */
2905         gtk_table_attach(GTK_TABLE(table),
2906                 table2 = gtk_table_new(2, 2, FALSE),
2907                 0, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2908
2909         /* Origin. */
2910         gtk_table_attach(GTK_TABLE(table2),
2911                 oti.rad_use_text = gtk_radio_button_new_with_label_from_widget(
2912                     GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")),
2913                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2914         gtk_table_attach(GTK_TABLE(table2),
2915                 oti.txt_origin = gtk_entry_new(),
2916                 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2917         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_origin), 25);
2918 #ifndef LEGACY
2919         g_object_set(G_OBJECT(oti.txt_origin), "hildon-input-mode",
2920                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2921 #else
2922         g_object_set(G_OBJECT(oti.txt_origin), HILDON_AUTOCAP, FALSE, NULL);
2923 #endif
2924
2925         /* Destination. */
2926         gtk_table_attach(GTK_TABLE(table2),
2927                 label = gtk_label_new(_("Query")),
2928                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2929         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2930         gtk_table_attach(GTK_TABLE(table2),
2931                 oti.txt_query = gtk_entry_new(),
2932                 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2933         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_query), 25);
2934 #ifndef LEGACY
2935         g_object_set(G_OBJECT(oti.txt_query), "hildon-input-mode",
2936                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2937 #else
2938         g_object_set(G_OBJECT(oti.txt_query), HILDON_AUTOCAP, FALSE, NULL);
2939 #endif
2940
2941         /* Set up auto-completion. */
2942         origin_comp = gtk_entry_completion_new();
2943         gtk_entry_completion_set_model(origin_comp,GTK_TREE_MODEL(_loc_model));
2944         gtk_entry_completion_set_text_column(origin_comp, 0);
2945         gtk_entry_set_completion(GTK_ENTRY(oti.txt_origin), origin_comp);
2946
2947         g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled",
2948                           G_CALLBACK(origin_type_selected), &oti);
2949         g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled",
2950                           G_CALLBACK(origin_type_selected), &oti);
2951         g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled",
2952                           G_CALLBACK(origin_type_selected), &oti);
2953     }
2954
2955     /* Initialize fields. */
2956
2957     if(unity != 0)
2958     {
2959         gchar buffer[80];
2960         gchar strlat[32];
2961         gchar strlon[32];
2962         gdouble lat, lon;
2963
2964         unit2latlon(unitx, unity, lat, lon);
2965
2966         g_ascii_formatd(strlat, 32, "%.06f", lat);
2967         g_ascii_formatd(strlon, 32, "%.06f", lon);
2968         snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
2969
2970         gtk_entry_set_text(GTK_ENTRY(oti.txt_origin), buffer);
2971         gtk_toggle_button_set_active(
2972                 GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2973     }
2974     /* Else use "End of Route" by default if they have a route. */
2975     else if(_route.head != _route.tail)
2976     {
2977         /* There is no route, so make it the default. */
2978         gtk_widget_set_sensitive(oti.rad_use_route, TRUE);
2979         gtk_toggle_button_set_active(
2980                 GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
2981         gtk_widget_grab_focus(oti.rad_use_route);
2982     }
2983     /* Else use "GPS Location" if they have GPS enabled. */
2984     else
2985     {
2986         /* There is no route, so desensitize "Use End of Route." */
2987         gtk_widget_set_sensitive(oti.rad_use_route, FALSE);
2988         if(_enable_gps)
2989         {
2990             gtk_toggle_button_set_active(
2991                     GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
2992             gtk_widget_grab_focus(oti.rad_use_gps);
2993         }
2994         /* Else use text. */
2995         else
2996         {
2997             gtk_toggle_button_set_active(
2998                     GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2999             gtk_widget_grab_focus(oti.txt_origin);
3000         }
3001     }
3002
3003     gtk_widget_show_all(dialog);
3004
3005     while(gtk_dialog_run(GTK_DIALOG(dialog)) ==GTK_RESPONSE_ACCEPT)
3006     {
3007         gchar buffer[BUFFER_SIZE];
3008         const gchar *origin, *query;
3009         gdouble lat, lon;
3010         GList *poi_list = NULL;
3011         gint cat_id;
3012         gboolean is_cat = FALSE;
3013         sqlite3_stmt *stmt;
3014
3015         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)))
3016         {
3017             gchar strlat[32];
3018             gchar strlon[32];
3019             latlon2unit(_gps.lat, _gps.lon, unitx, unity);
3020             g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
3021             g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
3022             snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
3023             origin = buffer;
3024         }
3025         else if(gtk_toggle_button_get_active(
3026                     GTK_TOGGLE_BUTTON(oti.rad_use_route)))
3027         {
3028             gchar strlat[32];
3029             gchar strlon[32];
3030             Point *p;
3031             gdouble lat, lon;
3032
3033             /* Use last non-zero route point. */
3034             for(p = _route.tail; !p->unity; p--) { }
3035
3036             unitx = p->unitx;
3037             unity = p->unity;
3038             unit2latlon(p->unitx, p->unity, lat, lon);
3039             g_ascii_formatd(strlat, 32, "%.06f", lat);
3040             g_ascii_formatd(strlon, 32, "%.06f", lon);
3041             snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
3042             origin = buffer;
3043         }
3044         else
3045         {
3046             Point porig;
3047             origin = gtk_entry_get_text(GTK_ENTRY(oti.txt_origin));
3048             porig = locate_address(dialog, origin);
3049             if(!porig.unity)
3050                 continue;
3051         }
3052
3053         if(!strlen(origin))
3054         {
3055             popup_error(dialog, _("Please specify an origin."));
3056             continue;
3057         }
3058
3059         /* Check if we're doing a category search. */
3060         {
3061             GtkTreeIter iter;
3062             if(gtk_combo_box_get_active_iter(
3063                     GTK_COMBO_BOX(cmb_category), &iter))
3064             {
3065                 gtk_tree_model_get(
3066                         gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
3067                         &iter, 0, &cat_id, -1);
3068                 if(cat_id >= 0)
3069                 {
3070                     is_cat = TRUE;
3071                 }
3072             }
3073         }
3074
3075         query = g_strdup_printf("%%%s%%",
3076                 gtk_entry_get_text(GTK_ENTRY(oti.txt_query)));
3077
3078         unit2latlon(unitx, unity, lat, lon);
3079
3080         if(is_cat)
3081         {
3082             if(SQLITE_OK != sqlite3_bind_int(_stmt_browsecat_poi, 1, cat_id) ||
3083                SQLITE_OK != sqlite3_bind_text(_stmt_browsecat_poi, 2, query,
3084                    -1, g_free) ||
3085                SQLITE_OK != sqlite3_bind_double(_stmt_browsecat_poi, 3, lat) ||
3086                SQLITE_OK != sqlite3_bind_double(_stmt_browsecat_poi, 4, lon))
3087             {
3088                 g_printerr("Failed to bind values for _stmt_browsecat_poi\n");
3089                 continue;
3090             }
3091             stmt = _stmt_browsecat_poi;
3092         }
3093         else
3094         {
3095             if(SQLITE_OK != sqlite3_bind_text(_stmt_browse_poi, 1, query,
3096                         -1, g_free) ||
3097                SQLITE_OK != sqlite3_bind_double(_stmt_browse_poi, 2, lat) ||
3098                SQLITE_OK != sqlite3_bind_double(_stmt_browse_poi, 3, lon))
3099             {
3100                 g_printerr("Failed to bind values for _stmt_browse_poi\n");
3101                 continue;
3102             }
3103             stmt = _stmt_browse_poi;
3104         }
3105
3106         while(SQLITE_ROW == sqlite3_step(stmt))
3107         {
3108             PoiInfo *poi = g_slice_new(PoiInfo);
3109             poi->poi_id = sqlite3_column_int(stmt, 0);
3110             poi->cat_id = sqlite3_column_int(stmt, 1);
3111             poi->lat = sqlite3_column_double(stmt, 2);
3112             poi->lon = sqlite3_column_double(stmt, 3);
3113             poi->label =g_strdup(sqlite3_column_text(stmt, 4));
3114             poi->desc = g_strdup(sqlite3_column_text(stmt, 5));
3115             poi->clabel=g_strdup(sqlite3_column_text(stmt, 6));
3116             poi_list = g_list_prepend(poi_list, poi);
3117         }
3118         sqlite3_reset(stmt);
3119
3120         if(poi_list)
3121         {
3122             /* Create a new dialog with the results. */
3123             poi_list_dialog(dialog, unitx, unity, poi_list);
3124             poi_list_free(poi_list);
3125         }
3126         else
3127             popup_error(dialog, _("No POIs found."));
3128     }
3129
3130     map_force_redraw();
3131
3132     /* Hide the dialog. */
3133     gtk_widget_hide(dialog);
3134
3135     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3136     return TRUE;
3137 }
3138
3139 /**
3140  * Render all the POI data.  This should be done before rendering track data.
3141  */
3142 void
3143 map_render_poi()
3144 {
3145     gint unitx, unity;
3146     gdouble lat1, lat2, lon1, lon2;
3147     gchar buffer[100];
3148     gint poix, poiy;
3149     GdkPixbuf *pixbuf = NULL;
3150     GError *error = NULL;
3151     printf("%s()\n", __PRETTY_FUNCTION__);
3152
3153     if(_poi_db && _poi_zoom > _zoom)
3154     {
3155         gint diag_offset = pixel2unit(MAX(_view_width_pixels,
3156                     _view_height_pixels) / 2);
3157         buf2unit(0, _view_height_pixels, unitx, unity);
3158         unitx = _center.unitx - diag_offset;
3159         unity = _center.unity + diag_offset;
3160         unit2latlon(unitx, unity, lat1, lon1);
3161         unitx = _center.unitx + diag_offset;
3162         unity = _center.unity - diag_offset;
3163         unit2latlon(unitx, unity, lat2, lon2);
3164
3165         if(SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 1, lat1) ||
3166            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 2, lat2) ||
3167            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 3, lon1) ||
3168            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 4, lon2))
3169         {
3170             g_printerr("Failed to bind values for _stmt_select_poi\n");
3171             return;
3172         }
3173
3174         while(SQLITE_ROW == sqlite3_step(_stmt_select_poi))
3175         {
3176             lat1 = sqlite3_column_double(_stmt_select_poi, 0);
3177             lon1 = sqlite3_column_double(_stmt_select_poi, 1);
3178             gchar *poi_label = g_utf8_strdown(sqlite3_column_text(
3179                     _stmt_select_poi, 3), -1);
3180             gchar *cat_label = g_utf8_strdown(sqlite3_column_text(
3181                     _stmt_select_poi, 6), -1);
3182
3183             latlon2unit(lat1, lon1, unitx, unity);
3184             unit2buf(unitx, unity, poix, poiy);
3185
3186             /* Try to get icon for specific POI first. */
3187             snprintf(buffer, sizeof(buffer), "%s/%s.jpg",
3188                     _poi_db_dirname, poi_label);
3189             pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3190             if(error)
3191             {
3192                 /* No icon for specific POI - try for category. */
3193                 error = NULL;
3194                 snprintf(buffer, sizeof(buffer), "%s/%s.jpg",
3195                         _poi_db_dirname, cat_label);
3196                 pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3197             }
3198             if(error)
3199             {
3200                 /* No icon for POI or for category.
3201                  * Try default POI icon file. */
3202                 error = NULL;
3203                 snprintf(buffer, sizeof(buffer), "%s/poi.jpg",
3204                         _poi_db_dirname);
3205                 pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3206             }
3207             if(error)
3208             {
3209                 /* No icon for POI or for category or default POI icon file.
3210                    Draw default purple square. */
3211                 error = NULL;
3212                 gdk_draw_rectangle(_map_pixmap, _gc[COLORABLE_POI], TRUE,
3213                         poix - (gint)(1.5f * _draw_width),
3214                         poiy - (gint)(1.5f * _draw_width),
3215                         3 * _draw_width,
3216                         3 * _draw_width);
3217             }
3218             else
3219             {
3220                 /* We found an icon to draw. */
3221                 gdk_draw_pixbuf(
3222                         _map_pixmap,
3223                         _gc[COLORABLE_POI],
3224                         pixbuf,
3225                         0, 0,
3226                         poix - gdk_pixbuf_get_width(pixbuf) / 2,
3227                         poiy - gdk_pixbuf_get_height(pixbuf) / 2,
3228                         -1,-1,
3229                         GDK_RGB_DITHER_NONE, 0, 0);
3230                 g_object_unref(pixbuf);
3231             }
3232
3233             g_free(poi_label);
3234             g_free(cat_label);
3235         }
3236         sqlite3_reset(_stmt_select_poi);
3237     }
3238
3239     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3240 }
3241
3242 void
3243 poi_destroy()
3244 {
3245     printf("%s()\n", __PRETTY_FUNCTION__);
3246
3247     if(_poi_db) 
3248     { 
3249         sqlite3_close(_poi_db); 
3250         _poi_db = NULL; 
3251     }
3252
3253     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3254 }