]> git.itanic.dy.fi Git - maemo-mapper/blob - src/poi.c
* Fixed bug in editing POI categories (closes #2281).
[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     snprintf(buffer, sizeof(buffer), "%.06f", poi.lat);
1232     gtk_entry_set_text(GTK_ENTRY(txt_lat), buffer);
1233     snprintf(buffer, sizeof(buffer), "%.06f", poi.lon);
1234     gtk_entry_set_text(GTK_ENTRY(txt_lon), buffer);
1235
1236     /* Label */
1237     if(SQLITE_ROW == sqlite3_step(_stmt_nextlabel_poi))
1238         poi.label = g_strdup_printf("Point%06d",
1239                 sqlite3_column_int(_stmt_nextlabel_poi, 0));
1240     else
1241         poi.label = g_strdup("");
1242     sqlite3_reset(_stmt_nextlabel_poi);
1243     gtk_entry_set_text(GTK_ENTRY(txt_label), poi.label);
1244
1245     /* POI Desc. */
1246     gtk_text_buffer_set_text(desc_txt, "", -1);
1247
1248     /* Category. */
1249     {
1250         GtkTreeIter iter;
1251         gint cat_id = -1;
1252         gboolean had_cat_id = FALSE;
1253
1254         if(gtk_combo_box_get_active_iter(
1255                 GTK_COMBO_BOX(cmb_category), &iter))
1256         {
1257             gtk_tree_model_get(
1258                     gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),&iter,
1259                     0, &cat_id,
1260                     -1);
1261             had_cat_id = TRUE;
1262         }
1263         gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(
1264                         GTK_COMBO_BOX(cmb_category))));
1265         if(poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1266                     GTK_COMBO_BOX(cmb_category))), cat_id, &iter)
1267                 && had_cat_id)
1268         {
1269             gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
1270         }
1271     }
1272
1273     pcedit.dialog = dialog;
1274     pcedit.cmb_category = cmb_category;
1275     pcedit.cat_id = poi.cat_id;
1276
1277     gtk_widget_show_all(dialog);
1278
1279     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1280     {
1281         GtkTreeIter iter;
1282         const gchar *text;
1283         gchar *error_check;
1284
1285         text = gtk_entry_get_text(GTK_ENTRY(txt_lat));
1286         poi.lat = strdmstod(text, &error_check);
1287         if(text == error_check || poi.lat < -90. || poi.lat > 90.) {
1288             popup_error(dialog, _("Invalid Latitude"));
1289             continue;
1290         }
1291
1292         text = gtk_entry_get_text(GTK_ENTRY(txt_lon));
1293         poi.lon = strdmstod(text, &error_check);
1294         if(text == error_check || poi.lon < -180. || poi.lon > 180.) {
1295             popup_error(dialog, _("Invalid Longitude"));
1296             continue;
1297         }
1298
1299         if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
1300         {
1301             if(poi.label)
1302                 g_free(poi.label);
1303             poi.label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
1304         }
1305         else
1306         {
1307             popup_error(dialog, _("Please specify a name."));
1308             continue;
1309         }
1310
1311         if(!gtk_combo_box_get_active_iter(
1312                 GTK_COMBO_BOX(cmb_category), &iter))
1313         {
1314             popup_error(dialog, _("Please specify a category."));
1315             continue;
1316         }
1317
1318         gtk_text_buffer_get_iter_at_offset(desc_txt, &begin,0 );
1319         gtk_text_buffer_get_end_iter (desc_txt, &end);
1320         if(poi.desc)
1321             g_free(poi.desc);
1322         poi.desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
1323
1324         if(poi.clabel)
1325             g_free(poi.clabel);
1326         gtk_tree_model_get(
1327                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
1328                 0, &poi.cat_id,
1329                 1, &poi.clabel,
1330                 -1);
1331
1332         /* add poi */
1333         if(SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 1, poi.lat)
1334         || SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 2, poi.lon)
1335         || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 3, poi.label,
1336                -1, g_free)
1337         || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 4, poi.desc,
1338                -1, g_free)
1339         || SQLITE_OK != sqlite3_bind_int(_stmt_insert_poi, 5, poi.cat_id)
1340         || SQLITE_DONE != sqlite3_step(_stmt_insert_poi))
1341         {
1342             MACRO_BANNER_SHOW_INFO(parent, _("Error adding POI"));
1343         }
1344
1345         sqlite3_reset(_stmt_insert_poi);
1346
1347         /* We're done. */
1348         break;
1349     }
1350
1351     g_free(poi.label);
1352     g_free(poi.desc);
1353     g_free(dpoi.txt_label);
1354
1355     map_force_redraw();
1356
1357     gtk_widget_hide(dialog);
1358
1359     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1360     return !dpoi.deleted;
1361 }
1362
1363 gboolean
1364 poi_view_dialog(GtkWidget *parent, PoiInfo *poi)
1365 {
1366     gchar buffer[16];
1367     GtkTreeIter iter;
1368     static GtkWidget *dialog;
1369     static GtkWidget *table;
1370     static GtkWidget *label;
1371     static GtkWidget *txt_label;
1372     static GtkWidget *txt_lat;
1373     static GtkWidget *txt_lon;
1374     static GtkWidget *cmb_category;
1375     static GtkWidget *txt_desc;
1376     static GtkWidget *btn_delete = NULL;
1377     static GtkWidget *btn_catedit;
1378     static GtkWidget *hbox;
1379     static GtkWidget *txt_scroll;
1380     static GtkTextBuffer *desc_txt;
1381     static GtkTextIter begin, end;
1382     static DeletePOI dpoi = {NULL, NULL, 0};
1383     static PoiCategoryEditInfo pcedit;
1384     printf("%s()\n", __PRETTY_FUNCTION__);
1385
1386     if(dialog == NULL)
1387     {
1388         dialog = gtk_dialog_new_with_buttons(_("Edit POI"),
1389             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
1390             GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1391             NULL);
1392
1393         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
1394                 btn_delete = gtk_button_new_with_label(_("Delete...")));
1395
1396         gtk_dialog_add_button(GTK_DIALOG(dialog),
1397                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT);
1398
1399         /* Set the lat/lon strings. */
1400         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1401                 table = gtk_table_new(6, 4, FALSE), TRUE, TRUE, 0);
1402
1403         gtk_table_attach(GTK_TABLE(table),
1404                 label = gtk_label_new(_("Lat")),
1405                 0, 1, 0, 1, GTK_FILL, 0, 2, 0);
1406         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1407         gtk_table_attach(GTK_TABLE(table),
1408                 txt_lat = gtk_entry_new(),
1409                 1, 2, 0, 1, GTK_FILL, 0, 2, 0);
1410
1411         gtk_table_attach(GTK_TABLE(table),
1412                 label = gtk_label_new(_("Lon")),
1413                 2, 3, 0, 1, GTK_FILL, 0, 2, 0);
1414         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1415         gtk_table_attach(GTK_TABLE(table),
1416                 txt_lon = gtk_entry_new(),
1417                 3, 4, 0, 1, GTK_FILL, 0, 2, 0);
1418
1419         gtk_table_attach(GTK_TABLE(table),
1420                 label = gtk_label_new(_("Label")),
1421                 0, 1, 1, 2, GTK_FILL, 0, 2, 0);
1422         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1423         gtk_table_attach(GTK_TABLE(table),
1424                 txt_label = gtk_entry_new(),
1425                 1, 4, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1426
1427         gtk_table_attach(GTK_TABLE(table),
1428                 label = gtk_label_new(_("Category")),
1429                 0, 1, 3, 4, GTK_FILL, 0, 2, 0);
1430         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1431         gtk_table_attach(GTK_TABLE(table),
1432                 hbox = gtk_hbox_new(FALSE, 4),
1433                 1, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1434         gtk_box_pack_start(GTK_BOX(hbox),
1435                 cmb_category = poi_create_cat_combo(),
1436                 FALSE, FALSE, 0);
1437
1438         gtk_box_pack_start(GTK_BOX(hbox),
1439                 btn_catedit = gtk_button_new_with_label(
1440                     _("Edit Categories...")),
1441                 FALSE, FALSE, 0);
1442
1443         gtk_table_attach(GTK_TABLE(table),
1444                 label = gtk_label_new(_("Description")),
1445                 0, 1, 5, 6, GTK_FILL, GTK_FILL, 2, 0);
1446         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.0f);
1447
1448         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
1449         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
1450                 GTK_SHADOW_IN);
1451         gtk_table_attach(GTK_TABLE(table),
1452                 txt_scroll,
1453                 1, 4, 5, 6, GTK_EXPAND | GTK_FILL, 0, 2, 0);
1454
1455         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
1456                 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1457
1458         txt_desc = gtk_text_view_new ();
1459         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
1460
1461         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
1462         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 550, 120);
1463
1464         desc_txt = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txt_desc));
1465
1466         g_signal_connect(G_OBJECT(btn_delete), "clicked",
1467                           G_CALLBACK(poi_delete), &dpoi);
1468
1469         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
1470                 G_CALLBACK(poi_edit_cat), &pcedit);
1471     }
1472
1473     dpoi.dialog = dialog;
1474     dpoi.txt_label = g_strdup(poi->label);
1475     dpoi.id = poi->poi_id;
1476     dpoi.deleted = FALSE;
1477
1478     /* Lat/Lon */
1479     {
1480         gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
1481
1482         lat_format(poi_info->lat, tmp1);
1483         lon_format(poi_info->lon, tmp2);
1484
1485         gtk_entry_set_text(GTK_ENTRY(txt_lat), tmp2);
1486         gtk_entry_set_text(GTK_ENTRY(txt_lon), tmp1);
1487     }
1488
1489     /* label */
1490     gtk_entry_set_text(GTK_ENTRY(txt_label), poi->label);
1491
1492     /* poi_desc */
1493     gtk_text_buffer_set_text(desc_txt, poi->desc, -1);
1494
1495     /* Category. */
1496     gtk_list_store_clear(GTK_LIST_STORE(gtk_combo_box_get_model(
1497                     GTK_COMBO_BOX(cmb_category))));
1498     if(poi_populate_categories(GTK_LIST_STORE(gtk_combo_box_get_model(
1499                 GTK_COMBO_BOX(cmb_category))), poi->cat_id, &iter))
1500         gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
1501
1502     /* Connect Signals */
1503     pcedit.dialog = dialog;
1504     pcedit.cmb_category = cmb_category;
1505     pcedit.cat_id = poi->cat_id;
1506
1507     gtk_widget_show_all(dialog);
1508
1509     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1510     {
1511         const gchar *text;
1512         gchar *error_check;
1513
1514         text = gtk_entry_get_text(GTK_ENTRY(txt_lat));
1515         poi->lat = strdmstod(text, &error_check);
1516         if(text == error_check || poi->lat < -90. || poi->lat > 90.) {
1517             popup_error(dialog, _("Invalid Latitude"));
1518             continue;
1519         }
1520
1521         text = gtk_entry_get_text(GTK_ENTRY(txt_lon));
1522         poi->lon = strdmstod(text, &error_check);
1523         if(text == error_check || poi->lon < -180. || poi->lon > 180.) {
1524             popup_error(dialog, _("Invalid Longitude"));
1525             continue;
1526         }
1527
1528         if(strlen(gtk_entry_get_text(GTK_ENTRY(txt_label))))
1529         {
1530             if(poi->label)
1531                 g_free(poi->label);
1532             poi->label = g_strdup(gtk_entry_get_text(GTK_ENTRY(txt_label)));
1533         }
1534         else
1535         {
1536             popup_error(dialog, _("Please specify a name."));
1537             continue;
1538         }
1539
1540         if(!gtk_combo_box_get_active_iter(
1541                 GTK_COMBO_BOX(cmb_category), &iter))
1542         {
1543             popup_error(dialog, _("Please specify a category."));
1544             continue;
1545         }
1546
1547         gtk_text_buffer_get_iter_at_offset(desc_txt, &begin,0 );
1548         gtk_text_buffer_get_end_iter (desc_txt, &end);
1549         if(poi->desc)
1550             g_free(poi->desc);
1551         poi->desc = gtk_text_buffer_get_text(desc_txt, &begin, &end, TRUE);
1552
1553         if(poi->clabel)
1554             g_free(poi->clabel);
1555         gtk_tree_model_get(
1556                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
1557                 0, &poi->cat_id,
1558                 1, &poi->clabel,
1559                 -1);
1560
1561         /* edit poi */
1562         if(SQLITE_OK != sqlite3_bind_double(
1563                     _stmt_update_poi, 1, poi->lat) ||
1564            SQLITE_OK != sqlite3_bind_double(
1565                _stmt_update_poi, 2, poi->lon) ||
1566            SQLITE_OK != sqlite3_bind_text(_stmt_update_poi, 3, poi->label,
1567                     -1, SQLITE_STATIC) ||
1568            SQLITE_OK != sqlite3_bind_text(_stmt_update_poi, 4, poi->desc,
1569                -1, g_free) ||
1570            SQLITE_OK != sqlite3_bind_int(
1571                _stmt_update_poi, 5, poi->cat_id) ||
1572            SQLITE_OK != sqlite3_bind_int(
1573                _stmt_update_poi, 6, poi->poi_id) ||
1574            SQLITE_DONE != sqlite3_step(_stmt_update_poi))
1575         {
1576             MACRO_BANNER_SHOW_INFO(parent, _("Error updating POI"));
1577         }
1578
1579         sqlite3_reset(_stmt_update_poi);
1580
1581         /* We're done. */
1582         break;
1583     }
1584
1585     g_free(dpoi.txt_label);
1586
1587     map_force_redraw();
1588
1589     gtk_widget_hide(dialog); /* Destroying causes a crash.... ??? */
1590
1591     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1592     return !dpoi.deleted;
1593 }
1594
1595 static gint
1596 poi_list_insert(GtkWidget *parent, GList *poi_list, GtkComboBox *cmb_category)
1597 {
1598     gint default_cat_id;
1599     gchar *default_cat_label;
1600     gint num_inserts = 0;
1601     GList *curr;
1602     GtkTreeIter iter;
1603     printf("%s()\n", __PRETTY_FUNCTION__);
1604
1605     /* Get defaults from the given GtkComboBox */
1606     if(!gtk_combo_box_get_active_iter(
1607             GTK_COMBO_BOX(cmb_category), &iter))
1608     {
1609         vprintf("%s(): return 0\n", __PRETTY_FUNCTION__);
1610         return 0;
1611     }
1612     gtk_tree_model_get(
1613             gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
1614             &iter,
1615             0, &default_cat_id,
1616             1, &default_cat_label,
1617             -1);
1618
1619     /* Iterate through the data model and import as desired. */
1620     for(curr = poi_list; curr; )
1621     {
1622         PoiInfo *poi = curr->data;
1623         if(
1624         (    SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 1, poi->lat)
1625           || SQLITE_OK != sqlite3_bind_double(_stmt_insert_poi, 2, poi->lon)
1626           || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 3, poi->label,
1627              -1, SQLITE_STATIC)
1628           || SQLITE_OK != sqlite3_bind_text(_stmt_insert_poi, 4, poi->desc,
1629              -1, SQLITE_STATIC)
1630           || SQLITE_OK != sqlite3_bind_int(_stmt_insert_poi, 5,
1631               poi->cat_id = default_cat_id)
1632           || SQLITE_DONE != sqlite3_step(_stmt_insert_poi)
1633         ))
1634         {
1635             /* Failure. */
1636             GList *tmp = curr->next;
1637             if(poi->label)
1638                 g_free(poi->label);
1639             if(poi->desc)
1640                 g_free(poi->desc);
1641             g_slice_free(PoiInfo, poi);
1642             poi_list = g_list_delete_link(poi_list, curr);
1643             curr = tmp;
1644         }
1645         else
1646         {
1647             /* Success. */
1648             ++num_inserts;
1649             if(default_cat_label)
1650                 poi->clabel = g_strdup(default_cat_label);
1651             poi->poi_id = sqlite3_last_insert_rowid(_poi_db);
1652             curr = curr->next;
1653         }
1654         sqlite3_reset(_stmt_insert_poi);
1655     }
1656
1657     if(num_inserts)
1658     {
1659         gchar buffer[BUFFER_SIZE];
1660         map_force_redraw();
1661         snprintf(buffer, sizeof(buffer), "%d %s", num_inserts,
1662            _("POIs were added to the POI database.  The following screen will "
1663                "allow you to modify or delete any of the new POIs."));
1664         popup_error(parent, buffer);
1665     }
1666     else
1667     {
1668         popup_error(parent, _("No POIs were found."));
1669     }
1670
1671     if(default_cat_label)
1672         g_free(default_cat_label);
1673
1674     vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, num_inserts);
1675     return num_inserts;
1676 }
1677
1678 static void
1679 poi_list_free(GList *poi_list)
1680 {
1681     GList *curr;
1682     printf("%s()\n", __PRETTY_FUNCTION__);
1683
1684     for(curr = poi_list; curr; curr = curr->next)
1685     {
1686         PoiInfo *poi_info = curr->data;
1687         if(poi_info)
1688         {
1689             if(poi_info->label)
1690                 g_free(poi_info->label);
1691             if(poi_info->desc)
1692                 g_free(poi_info->desc);
1693             if(poi_info->clabel)
1694                 g_free(poi_info->clabel);
1695             g_slice_free(PoiInfo, poi_info);
1696         }
1697     }
1698
1699     g_list_free(poi_list);
1700
1701     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1702 }
1703
1704 static void
1705 poi_list_bearing_cell_data_func(
1706         GtkTreeViewColumn *tree_column,
1707         GtkCellRenderer *cell,
1708         GtkTreeModel *tree_model,
1709         GtkTreeIter *iter)
1710 {
1711     gchar buffer[80];
1712     gfloat f;
1713     vprintf("%s()\n", __PRETTY_FUNCTION__);
1714
1715     gtk_tree_model_get(tree_model, iter, POI_BEARING, &f, -1);
1716     snprintf(buffer, sizeof(buffer), "%.1f", f);
1717     g_object_set(cell, "text", buffer, NULL);
1718
1719     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1720 }
1721
1722 static void
1723 poi_list_distance_cell_data_func(
1724         GtkTreeViewColumn *tree_column,
1725         GtkCellRenderer *cell,
1726         GtkTreeModel *tree_model,
1727         GtkTreeIter *iter)
1728 {
1729     gchar buffer[80];
1730     gfloat f;
1731     vprintf("%s()\n", __PRETTY_FUNCTION__);
1732
1733     gtk_tree_model_get(tree_model, iter, POI_DISTANCE, &f, -1);
1734     snprintf(buffer, sizeof(buffer), "%.2f", f);
1735     g_object_set(cell, "text", buffer, NULL);
1736
1737     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1738 }
1739
1740 static gboolean
1741 poi_list_row_selected(GtkCellRendererToggle *renderer,
1742         gchar *path_string, GtkTreeModel *tree_model)
1743 {
1744     GtkTreeIter iter;
1745     vprintf("%s()\n", __PRETTY_FUNCTION__);
1746
1747     if(gtk_tree_model_get_iter_from_string(tree_model, &iter, path_string))
1748     {
1749         gboolean old_value;
1750         gtk_tree_model_get(tree_model, &iter, POI_SELECTED, &old_value, -1);
1751         gtk_list_store_set(GTK_LIST_STORE(tree_model), &iter,
1752                 POI_SELECTED, !old_value,
1753                 -1);
1754     }
1755
1756     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1757     return TRUE;
1758 }
1759
1760 static gboolean
1761 poi_list_set_category(GtkWidget *widget, PoiListInfo *pli)
1762 {
1763     static GtkWidget *dialog = NULL;
1764     static GtkWidget *cmb_category = NULL;
1765     static GtkWidget *btn_catedit = NULL;
1766     static PoiCategoryEditInfo pcedit;
1767     printf("%s()\n", __PRETTY_FUNCTION__);
1768
1769     if(dialog == NULL)
1770     {
1771         GtkWidget *hbox;
1772         GtkWidget *label;
1773
1774         dialog = gtk_dialog_new_with_buttons(_("Set Category..."),
1775                 GTK_WINDOW(pli->dialog2), GTK_DIALOG_MODAL,
1776                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1777                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1778                 NULL);
1779
1780         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1781                 hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
1782
1783         gtk_box_pack_start(GTK_BOX(hbox),
1784                 label = gtk_label_new(_("Category")),
1785                 FALSE, FALSE, 0);
1786
1787         gtk_box_pack_start(GTK_BOX(hbox),
1788                 cmb_category = poi_create_cat_combo(),
1789                 FALSE, FALSE, 4);
1790
1791         gtk_box_pack_start(GTK_BOX(hbox),
1792                 btn_catedit = gtk_button_new_with_label(
1793                     _("Edit Categories...")),
1794                 FALSE, FALSE, 0);
1795
1796         /* Connect Signals */
1797         pcedit.dialog = dialog;
1798         pcedit.cmb_category = cmb_category;
1799         pcedit.cat_id = -1;
1800         g_signal_connect(G_OBJECT(btn_catedit), "clicked",
1801                 G_CALLBACK(poi_edit_cat), &pcedit);
1802     }
1803
1804     gtk_widget_show_all(dialog);
1805
1806     while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1807     {
1808         GtkTreeIter iter;
1809         GtkListStore *store;
1810         gint cat_id;
1811         const gchar *cat_label;
1812
1813         /* Get the text of the chosen category. */
1814         if(!gtk_combo_box_get_active_iter(
1815                 GTK_COMBO_BOX(cmb_category), &iter))
1816         {
1817             popup_error(dialog, _("Please specify a category."));
1818             continue;
1819         }
1820
1821         gtk_tree_model_get(
1822                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
1823                 &iter,
1824                 0, &cat_id,
1825                 1, &cat_label,
1826                 -1);
1827
1828         /* Iterate through the data store and categorize as desired. */
1829         store = GTK_LIST_STORE(gtk_tree_view_get_model(
1830                     GTK_TREE_VIEW(pli->tree_view)));
1831         if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
1832         {
1833             PoiInfo poi;
1834             gboolean selected;
1835
1836             memset(&poi, 0, sizeof(poi));
1837
1838             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1839                     POI_SELECTED, &selected,
1840                     POI_POIID, &(poi.poi_id),
1841                     POI_LAT, &(poi.lat),
1842                     POI_LON, &(poi.lon),
1843                     POI_LABEL, &(poi.label),
1844                     POI_DESC, &(poi.desc),
1845                     -1);
1846
1847             if(selected)
1848             {
1849                 gtk_list_store_set(store, &iter,
1850                     POI_CATID, cat_id,
1851                     POI_CLABEL, cat_label,
1852                     -1);
1853                 /* edit poi */
1854                 if(SQLITE_OK != sqlite3_bind_double(
1855                             _stmt_update_poi, 1, poi.lat) ||
1856                    SQLITE_OK != sqlite3_bind_double(
1857                        _stmt_update_poi, 2, poi.lon) ||
1858                    SQLITE_OK != sqlite3_bind_text(_stmt_update_poi,
1859                        3, poi.label, -1, SQLITE_STATIC) ||
1860                    SQLITE_OK != sqlite3_bind_text(_stmt_update_poi,
1861                        4, poi.desc, -1, SQLITE_STATIC) ||
1862                    SQLITE_OK != sqlite3_bind_int(
1863                        _stmt_update_poi, 5, cat_id) ||
1864                    SQLITE_OK != sqlite3_bind_int(
1865                        _stmt_update_poi, 6, poi.poi_id) ||
1866                    SQLITE_DONE != sqlite3_step(_stmt_update_poi))
1867                 {
1868                     MACRO_BANNER_SHOW_INFO(pli->dialog2,
1869                             _("Error updating POI"));
1870                 }
1871                 sqlite3_reset(_stmt_update_poi);
1872             }
1873         } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
1874
1875         break;
1876     }
1877
1878     map_force_redraw();
1879     gtk_widget_hide(dialog);
1880
1881     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1882     return TRUE;
1883 }
1884
1885 static gboolean
1886 poi_list_select_all(GtkTreeViewColumn *column, PoiListInfo *pli)
1887 {
1888     GtkTreeIter iter;
1889     GtkListStore *store;
1890     printf("%s()\n", __PRETTY_FUNCTION__);
1891
1892     /* Iterate through the data store and select as desired. */
1893     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1894                 GTK_TREE_VIEW(pli->tree_view)));
1895     if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
1896     {
1897         gtk_list_store_set(store, &iter,
1898             POI_SELECTED, pli->select_all,
1899             -1);
1900     } while(gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
1901
1902     pli->select_all = !pli->select_all;
1903
1904     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1905     return TRUE;
1906 }
1907
1908 static gboolean
1909 poi_list_view(GtkWidget *widget, PoiListInfo *pli)
1910 {
1911     GtkTreeIter iter;
1912     GtkTreeSelection *selection;
1913     GtkListStore *store;
1914     printf("%s()\n", __PRETTY_FUNCTION__);
1915
1916     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pli->tree_view));
1917     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1918                 GTK_TREE_VIEW(pli->tree_view)));
1919
1920     /* Iterate through the data store and import as desired. */
1921     if(gtk_tree_selection_get_selected(selection, NULL, &iter))
1922     {
1923         PoiInfo poi;
1924         memset(&poi, 0, sizeof(poi));
1925
1926         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1927                 POI_POIID, &(poi.poi_id),
1928                 POI_CATID, &(poi.cat_id),
1929                 POI_LAT, &(poi.lat),
1930                 POI_LON, &(poi.lon),
1931                 POI_LABEL, &(poi.label),
1932                 POI_DESC, &(poi.desc),
1933                 POI_CLABEL, &(poi.clabel),
1934                 -1);
1935
1936         if(poi_view_dialog(pli->dialog, &poi))
1937         {
1938             gtk_list_store_set(store, &iter,
1939                     POI_POIID, poi.poi_id,
1940                     POI_CATID, poi.cat_id,
1941                     POI_LAT, poi.lat,
1942                     POI_LON, poi.lon,
1943                     POI_LABEL, poi.label,
1944                     POI_DESC, poi.desc,
1945                     POI_CLABEL, poi.clabel,
1946                     -1);
1947         }
1948         else
1949         {
1950             /* POI was deleted. */
1951             gtk_list_store_remove(store, &iter);
1952         }
1953     }
1954
1955     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1956     return TRUE;
1957 }
1958
1959 static void
1960 poi_list_row_activated(GtkTreeView *tree_view, GtkTreePath *path,
1961         GtkTreeViewColumn *column, PoiListInfo *pli)
1962 {
1963     printf("%s()\n", __PRETTY_FUNCTION__);
1964
1965     if(column != pli->select_column)
1966         poi_list_view(GTK_WIDGET(tree_view), pli);
1967
1968     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1969 }
1970
1971 static gboolean
1972 poi_list_goto(GtkWidget *widget, PoiListInfo *pli)
1973 {
1974     GtkTreeIter iter;
1975     GtkTreeSelection *selection;
1976     GtkListStore *store;
1977     printf("%s()\n", __PRETTY_FUNCTION__);
1978
1979     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(pli->tree_view));
1980     store = GTK_LIST_STORE(gtk_tree_view_get_model(
1981                 GTK_TREE_VIEW(pli->tree_view)));
1982
1983     /* Iterate through the data store and import as desired. */
1984     if(gtk_tree_selection_get_selected(selection, NULL, &iter))
1985     {
1986         gdouble lat, lon;
1987         Point unit;
1988
1989         gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
1990                 POI_LAT, &lat,
1991                 POI_LON, &lon,
1992                 -1);
1993
1994         latlon2unit(lat, lon, unit.unitx, unit.unity);
1995
1996         if(_center_mode > 0)
1997             gtk_check_menu_item_set_active(
1998                     GTK_CHECK_MENU_ITEM(_menu_view_ac_none_item), TRUE);
1999
2000         map_center_unit(unit);
2001     }
2002
2003     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2004     return TRUE;
2005 }
2006
2007 static gboolean
2008 poi_list_delete(GtkWidget *widget, PoiListInfo *pli)
2009 {
2010     GtkWidget *confirm;
2011     printf("%s()\n", __PRETTY_FUNCTION__);
2012
2013     confirm = hildon_note_new_confirmation(
2014             GTK_WINDOW(pli->dialog2), _("Delete selected POI?"));
2015
2016     if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2017     {
2018         GtkTreeIter iter;
2019         GtkListStore *store;
2020         gboolean already_next;
2021         gboolean must_iterate;;
2022
2023         /* Iterate through the data store and import as desired. */
2024         store = GTK_LIST_STORE(gtk_tree_view_get_model(
2025                     GTK_TREE_VIEW(pli->tree_view)));
2026         if(gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) do
2027         {
2028             gboolean selected;
2029             must_iterate = TRUE;
2030             already_next = FALSE;
2031             gint poi_id;
2032             gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
2033                 POI_SELECTED, &selected,
2034                 POI_POIID, &poi_id,
2035                 -1);
2036             if(selected)
2037             {
2038                 /* Delete POI. */
2039                 if(SQLITE_OK != sqlite3_bind_int(_stmt_delete_poi, 1, poi_id)
2040                 || SQLITE_DONE != sqlite3_step(_stmt_delete_poi))
2041                 {
2042                     MACRO_BANNER_SHOW_INFO(pli->dialog2,
2043                             _("Error deleting POI"));
2044                 }
2045                 else
2046                 {
2047                     already_next = gtk_list_store_remove(store, &iter);
2048                     must_iterate = FALSE;
2049                 }
2050                 sqlite3_reset(_stmt_delete_poi);
2051             }
2052         } while(already_next || (must_iterate
2053                 && gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)));
2054     }
2055
2056     map_force_redraw();
2057
2058     gtk_widget_destroy(confirm);
2059
2060     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2061     return TRUE;
2062 }
2063
2064 static gboolean
2065 poi_list_export_gpx(GtkWidget *widget, PoiListInfo *pli)
2066 {
2067     GnomeVFSHandle *handle;
2068     printf("%s()\n", __PRETTY_FUNCTION__);
2069
2070     if(display_open_file(pli->dialog2, NULL, &handle, NULL, NULL, NULL,
2071                     GTK_FILE_CHOOSER_ACTION_SAVE))
2072     {
2073         gint num_exported = gpx_poi_write(
2074                gtk_tree_view_get_model(GTK_TREE_VIEW(pli->tree_view)), handle);
2075         if(num_exported >= 0)
2076         {
2077             gchar buffer[80];
2078             snprintf(buffer, sizeof(buffer), "%d %s\n", num_exported,
2079                     _("POIs Exported"));
2080             MACRO_BANNER_SHOW_INFO(pli->dialog2, buffer);
2081         }
2082         else
2083             popup_error(pli->dialog2, _("Error writing GPX file."));
2084         gnome_vfs_close(handle);
2085     }
2086
2087     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2088     return TRUE;
2089 }
2090
2091 static gboolean
2092 poi_list_manage_checks(GtkWidget *widget, PoiListInfo *pli)
2093 {
2094     GtkWidget *btn_category;
2095     GtkWidget *btn_delete;
2096     GtkWidget *btn_export_gpx;
2097
2098     printf("%s()\n", __PRETTY_FUNCTION__);
2099
2100     pli->dialog2 = gtk_dialog_new_with_buttons(_("Checked POI Actions..."),
2101             GTK_WINDOW(pli->dialog), GTK_DIALOG_MODAL,
2102             NULL);
2103
2104     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2105             gtk_label_new(_("Select an operation to perform\n"
2106                             "on the POIs that you checked\n"
2107                             "in the POI list.")),
2108                 FALSE, FALSE, 4);
2109
2110     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2111             btn_category = gtk_button_new_with_label(_("Set Category...")),
2112                 FALSE, FALSE, 4);
2113
2114     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2115             btn_delete = gtk_button_new_with_label(_("Delete...")),
2116                 FALSE, FALSE, 4);
2117
2118     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli->dialog2)->vbox),
2119             btn_export_gpx = gtk_button_new_with_label(
2120                 _("Export to GPX...")),
2121                 FALSE, FALSE, 4);
2122
2123     gtk_dialog_add_button(GTK_DIALOG(pli->dialog2),
2124             GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT);
2125
2126     g_signal_connect(G_OBJECT(btn_category), "clicked",
2127             G_CALLBACK(poi_list_set_category), pli);
2128
2129     g_signal_connect(G_OBJECT(btn_delete), "clicked",
2130             G_CALLBACK(poi_list_delete), pli);
2131
2132     g_signal_connect(G_OBJECT(btn_export_gpx), "clicked",
2133             G_CALLBACK(poi_list_export_gpx), pli);
2134
2135     gtk_widget_show_all(pli->dialog2);
2136
2137     gtk_dialog_run(GTK_DIALOG(pli->dialog2));
2138
2139     gtk_widget_destroy(pli->dialog2);
2140     pli->dialog2 = NULL;
2141
2142     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2143     return TRUE;
2144 }
2145
2146 static gboolean
2147 poi_list_dialog(GtkWidget *parent, gint unitx, gint unity, GList *poi_list)
2148 {
2149     static PoiListInfo pli = { NULL, NULL };
2150     static GtkWidget *scroller;
2151     static GtkWidget *btn_goto;
2152     static GtkWidget *btn_edit;
2153     static GtkWidget *btn_manage_checks;
2154     static GtkListStore *store;
2155     GtkTreeIter iter;
2156     GList *curr;
2157     gdouble src_lat, src_lon;
2158     printf("%s()\n", __PRETTY_FUNCTION__);
2159
2160     if(pli.dialog == NULL)
2161     {
2162         GtkCellRenderer *renderer;
2163         GtkTreeViewColumn *column;
2164
2165         pli.dialog = gtk_dialog_new_with_buttons(_("POI List"),
2166             GTK_WINDOW(parent), GTK_DIALOG_MODAL,
2167                 NULL);
2168
2169         store = gtk_list_store_new(POI_NUM_COLUMNS,
2170                                    G_TYPE_BOOLEAN,/* Selected */
2171                                    G_TYPE_INT,    /* POI ID */
2172                                    G_TYPE_INT,    /* Category ID */
2173                                    G_TYPE_DOUBLE, /* Latitude */
2174                                    G_TYPE_DOUBLE, /* Longitude */
2175                                    G_TYPE_STRING, /* Lat/Lon */
2176                                    G_TYPE_FLOAT,  /* Bearing */
2177                                    G_TYPE_FLOAT,  /* Distance */
2178                                    G_TYPE_STRING, /* POI Label */
2179                                    G_TYPE_STRING, /* POI Desc. */
2180                                    G_TYPE_STRING);/* Category Label */
2181
2182         /* Set up the tree view. */
2183         pli.tree_view = gtk_tree_view_new();
2184         g_object_set(G_OBJECT(pli.tree_view),
2185                 "allow-checkbox-mode", FALSE, NULL);
2186
2187         gtk_tree_selection_set_mode(
2188                 gtk_tree_view_get_selection(GTK_TREE_VIEW(pli.tree_view)),
2189                 GTK_SELECTION_SINGLE);
2190         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(pli.tree_view), TRUE);
2191
2192         renderer = gtk_cell_renderer_toggle_new();
2193         gtk_cell_renderer_toggle_set_active(GTK_CELL_RENDERER_TOGGLE(renderer),
2194                 TRUE);
2195         g_signal_connect(G_OBJECT(renderer), "toggled",
2196                 G_CALLBACK(poi_list_row_selected), store);
2197         pli.select_column = gtk_tree_view_column_new_with_attributes(
2198                 "*", renderer, "active", POI_SELECTED, NULL);
2199         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view),
2200                 pli.select_column);
2201         gtk_tree_view_column_set_clickable(pli.select_column, TRUE);
2202         g_signal_connect(G_OBJECT(pli.select_column), "clicked",
2203                 G_CALLBACK(poi_list_select_all), &pli);
2204
2205         renderer = gtk_cell_renderer_combo_new();
2206         column = gtk_tree_view_column_new_with_attributes(
2207                 _("Category"), renderer, "text", POI_CLABEL, NULL);
2208         gtk_tree_view_column_set_sizing(column,GTK_TREE_VIEW_COLUMN_GROW_ONLY);
2209         gtk_tree_view_column_set_sort_column_id(column, POI_CLABEL);
2210         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2211
2212         renderer = gtk_cell_renderer_text_new();
2213         g_object_set(renderer, "xalign", 1.f, NULL);
2214         column = gtk_tree_view_column_new_with_attributes(
2215                 _("Dist."), renderer, "text", POI_DISTANCE, NULL);
2216         gtk_tree_view_column_set_cell_data_func(column, renderer,
2217                 (GtkTreeCellDataFunc)poi_list_distance_cell_data_func,
2218                 NULL, NULL);
2219         gtk_tree_view_column_set_sort_column_id(column, POI_DISTANCE);
2220         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2221
2222         renderer = gtk_cell_renderer_text_new();
2223         g_object_set(renderer, "xalign", 1.f, NULL);
2224         column = gtk_tree_view_column_new_with_attributes(
2225                 _("Bear."), renderer, "text", POI_BEARING, NULL);
2226         gtk_tree_view_column_set_cell_data_func(column, renderer,
2227                 (GtkTreeCellDataFunc)poi_list_bearing_cell_data_func,
2228                 NULL, NULL);
2229         gtk_tree_view_column_set_sort_column_id(column, POI_BEARING);
2230         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2231
2232         renderer = gtk_cell_renderer_text_new();
2233         column = gtk_tree_view_column_new_with_attributes(
2234                 _("Label"), renderer, "text", POI_LABEL, NULL);
2235         gtk_tree_view_column_set_sort_column_id(column, POI_LABEL);
2236         gtk_tree_view_append_column(GTK_TREE_VIEW(pli.tree_view), column);
2237
2238         g_signal_connect(G_OBJECT(pli.tree_view), "row-activated",
2239                 G_CALLBACK(poi_list_row_activated), &pli);
2240
2241         gtk_tree_view_set_model(GTK_TREE_VIEW(pli.tree_view),
2242                 GTK_TREE_MODEL(store));
2243         g_object_unref(G_OBJECT(store));
2244
2245         /* Enable the help button. */
2246 #ifndef LEGACY
2247         hildon_help_dialog_help_enable(
2248 #else
2249         ossohelp_dialog_help_enable(
2250 #endif
2251                 GTK_DIALOG(pli.dialog), HELP_ID_POILIST, _osso);
2252
2253         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2254                 btn_goto = gtk_button_new_with_label(_("Go to")));
2255
2256         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2257                 btn_edit = gtk_button_new_with_label(_("Edit...")));
2258
2259         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(pli.dialog)->action_area),
2260                 btn_manage_checks = gtk_button_new_with_label(
2261                     _("Checked POI Actions...")));
2262
2263         gtk_dialog_add_button(GTK_DIALOG(pli.dialog),
2264                 GTK_STOCK_CLOSE, GTK_RESPONSE_ACCEPT);
2265
2266         gtk_window_set_default_size(GTK_WINDOW(pli.dialog), 500, 400);
2267
2268         scroller = gtk_scrolled_window_new (NULL, NULL);
2269         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroller),
2270                 GTK_SHADOW_ETCHED_IN);
2271         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroller),
2272                 GTK_POLICY_NEVER,
2273                 GTK_POLICY_AUTOMATIC);
2274         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(pli.dialog)->vbox),
2275                 scroller, TRUE, TRUE, 0);
2276
2277         gtk_container_add(GTK_CONTAINER(scroller), pli.tree_view);
2278
2279         g_signal_connect(G_OBJECT(btn_goto), "clicked",
2280                 G_CALLBACK(poi_list_goto), &pli);
2281
2282         g_signal_connect(G_OBJECT(btn_edit), "clicked",
2283                 G_CALLBACK(poi_list_view), &pli);
2284
2285         g_signal_connect(G_OBJECT(btn_manage_checks), "clicked",
2286                 G_CALLBACK(poi_list_manage_checks), &pli);
2287     }
2288
2289     /* Initialize the tree store. */
2290
2291     gtk_list_store_clear(store);
2292     pli.select_all = FALSE;
2293
2294     unit2latlon(unitx, unity, src_lat, src_lon);
2295
2296     for(curr = poi_list; curr; curr = curr->next)
2297     {
2298         PoiInfo *poi_info = curr->data;
2299         gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN];
2300
2301         printf("poi: (%f, %f, %s, %s)\n",
2302                 poi_info->lat, poi_info->lon,
2303                 poi_info->label, poi_info->desc);
2304
2305         lat_format(poi_info->lat, tmp1);
2306         lon_format(poi_info->lon, tmp2);
2307
2308         gtk_list_store_append(store, &iter);
2309         gtk_list_store_set(store, &iter,
2310                 POI_SELECTED, TRUE,
2311                 POI_POIID, poi_info->poi_id,
2312                 POI_LAT, poi_info->lat,
2313                 POI_LON, poi_info->lon,
2314                 POI_BEARING, calculate_bearing(src_lat, src_lon,
2315                     poi_info->lat, poi_info->lon),
2316                 POI_DISTANCE, calculate_distance(src_lat,src_lon,
2317                     poi_info->lat, poi_info->lon) * UNITS_CONVERT[_units],
2318                 POI_LABEL, poi_info->label,
2319                 POI_DESC, poi_info->desc,
2320                 POI_CATID, poi_info->cat_id,
2321                 POI_CLABEL, poi_info->clabel,
2322                 -1);
2323     }
2324
2325     gtk_widget_show_all(pli.dialog);
2326
2327     GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(pli.dialog));
2328
2329     map_force_redraw();
2330
2331     gtk_widget_hide(pli.dialog);
2332
2333     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2334     return TRUE;
2335 }
2336
2337 gboolean
2338 poi_import_dialog(gint unitx, gint unity)
2339 {
2340     GtkWidget *dialog = NULL;
2341     gboolean success = FALSE;
2342     printf("%s()\n", __PRETTY_FUNCTION__);
2343
2344     dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(_window),
2345             GTK_FILE_CHOOSER_ACTION_OPEN);
2346
2347     gtk_widget_show_all(dialog);
2348
2349     while(!success && gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK)
2350     {
2351         gchar *file_uri_str = NULL;
2352         gchar *bytes = NULL;
2353         gint size;
2354         GnomeVFSResult vfs_result;
2355         GList *poi_list = NULL;
2356
2357         file_uri_str = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog));
2358
2359         /* Parse the given file as GPX. */
2360         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2361                         file_uri_str, &size, &bytes)))
2362         {
2363             popup_error(dialog, gnome_vfs_result_to_string(vfs_result));
2364         }
2365         else if(gpx_poi_parse(bytes, size, &poi_list))
2366         {
2367             static GtkWidget *cat_dialog = NULL;
2368             static GtkWidget *cmb_category = NULL;
2369             static GtkWidget *btn_catedit = NULL;
2370             static PoiCategoryEditInfo pcedit;
2371
2372             if(!cat_dialog)
2373             {
2374                 GtkWidget *hbox;
2375                 GtkWidget *label;
2376                 cat_dialog = gtk_dialog_new_with_buttons(_("Default Category"),
2377                         GTK_WINDOW(dialog), GTK_DIALOG_MODAL,
2378                         GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2379                         GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2380                         NULL);
2381
2382                 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cat_dialog)->vbox),
2383                         hbox = gtk_hbox_new(FALSE, 4), FALSE, FALSE, 4);
2384
2385                 gtk_box_pack_start(GTK_BOX(hbox),
2386                         label = gtk_label_new(_("Category")),
2387                         FALSE, FALSE, 0);
2388
2389                 gtk_box_pack_start(GTK_BOX(hbox),
2390                         cmb_category = poi_create_cat_combo(),
2391                         FALSE, FALSE, 4);
2392
2393                 gtk_box_pack_start(GTK_BOX(hbox),
2394                         btn_catedit = gtk_button_new_with_label(
2395                             _("Edit Categories...")),
2396                         FALSE, FALSE, 0);
2397
2398                 /* Connect Signals */
2399                 pcedit.dialog = dialog;
2400                 pcedit.cmb_category = cmb_category;
2401                 pcedit.cat_id = -1;
2402                 g_signal_connect(G_OBJECT(btn_catedit), "clicked",
2403                         G_CALLBACK(poi_edit_cat), &pcedit);
2404             }
2405
2406             gtk_widget_show_all(cat_dialog);
2407
2408             while(GTK_RESPONSE_ACCEPT ==gtk_dialog_run(GTK_DIALOG(cat_dialog)))
2409             {
2410                 if(gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_category)) == -1)
2411                 {
2412                     popup_error(dialog,
2413                             _("Please specify a default category."));
2414                     continue;
2415                 }
2416
2417                 /* Insert the POIs into the database. */
2418                 gint num_inserts = poi_list_insert(dialog,
2419                         poi_list, GTK_COMBO_BOX(cmb_category));
2420
2421                 if(num_inserts)
2422                 {
2423                     /* Hide the dialogs. */
2424                     gtk_widget_hide(cat_dialog);
2425
2426                     /* Create a new dialog with the results. */
2427                     poi_list_dialog(dialog, unitx, unity, poi_list);
2428                     success = TRUE;
2429                 }
2430                 break;
2431             }
2432
2433             gtk_widget_hide(cat_dialog);
2434
2435             poi_list_free(poi_list);
2436         }
2437         else
2438             popup_error(dialog, _("Error parsing GPX file."));
2439
2440         g_free(file_uri_str);
2441         g_free(bytes);
2442     }
2443
2444     /* Hide the dialog. */
2445     gtk_widget_destroy(dialog);
2446
2447     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2448     return success;
2449 }
2450
2451 static gboolean
2452 poi_download_cat_selected(GtkComboBox *cmb_category, GtkEntry *txt_query)
2453 {
2454     GtkTreeIter iter;
2455     printf("%s()\n", __PRETTY_FUNCTION__);
2456
2457     if(gtk_combo_box_get_active_iter(GTK_COMBO_BOX(cmb_category), &iter))
2458     {
2459         gchar buffer[BUFFER_SIZE];
2460         GtkWidget *confirm = NULL;
2461         gchar *category = NULL;
2462
2463         gtk_tree_model_get(
2464                 gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)), &iter,
2465                 1, &category,
2466                 -1);
2467
2468         if(*gtk_entry_get_text(txt_query))
2469         {
2470             snprintf(buffer, sizeof(buffer), "%s\n  %s",
2471                     _("Overwrite query with the following text?"), category);
2472             confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),buffer);
2473
2474         }
2475
2476         if(confirm == NULL
2477                 || GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
2478             gtk_entry_set_text(txt_query, category);
2479
2480         if(confirm)
2481             gtk_widget_destroy(confirm);
2482     }
2483
2484     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2485     return TRUE;
2486 }
2487
2488
2489 static gboolean
2490 origin_type_selected(GtkWidget *toggle, OriginToggleInfo *oti)
2491 {
2492     printf("%s()\n", __PRETTY_FUNCTION__);
2493
2494     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
2495         gtk_widget_set_sensitive(oti->txt_origin, toggle == oti->rad_use_text);
2496
2497     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2498     return TRUE;
2499 }
2500
2501 gboolean
2502 poi_download_dialog(gint unitx, gint unity)
2503 {
2504     static GtkWidget *dialog = NULL;
2505     static GtkWidget *hbox = NULL;
2506     static GtkWidget *table = NULL;
2507     static GtkWidget *table2 = NULL;
2508     static GtkWidget *label = NULL;
2509     static GtkWidget *num_page = NULL;
2510     static GtkWidget *txt_source_url = NULL;
2511     static OriginToggleInfo oti;
2512     static GtkWidget *cmb_category;
2513     printf("%s()\n", __PRETTY_FUNCTION__);
2514
2515     conic_recommend_connected();
2516
2517     if(!dialog)
2518     {
2519         GtkEntryCompletion *origin_comp;
2520
2521         dialog = gtk_dialog_new_with_buttons(_("Download POIs"),
2522                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2523                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2524                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2525                 NULL);
2526
2527         /* Enable the help button. */
2528 #ifndef LEGACY
2529         hildon_help_dialog_help_enable(
2530 #else
2531         ossohelp_dialog_help_enable(
2532 #endif
2533                 GTK_DIALOG(dialog), HELP_ID_DOWNPOI, _osso);
2534
2535         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2536                 table = gtk_table_new(4, 4, FALSE), TRUE, TRUE, 0);
2537
2538         /* Source URL. */
2539         gtk_table_attach(GTK_TABLE(table),
2540                 hbox = gtk_hbox_new(FALSE, 4),
2541                 0, 4, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2542         gtk_box_pack_start(GTK_BOX(hbox),
2543                 label = gtk_label_new(_("Source URL")), FALSE, TRUE, 4);
2544         gtk_box_pack_start(GTK_BOX(hbox),
2545                 txt_source_url = gtk_entry_new(), TRUE, TRUE, 4);
2546
2547         /* Auto. */
2548         gtk_table_attach(GTK_TABLE(table),
2549                 oti.rad_use_gps = gtk_radio_button_new_with_label(NULL,
2550                     _("Use GPS Location")),
2551                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2552
2553         /* Use End of Route. */
2554         gtk_table_attach(GTK_TABLE(table),
2555                oti.rad_use_route = gtk_radio_button_new_with_label_from_widget(
2556                    GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")),
2557                0, 1, 2, 3, GTK_FILL, 0, 2, 4);
2558
2559
2560         gtk_table_attach(GTK_TABLE(table),
2561                 gtk_vseparator_new(),
2562                 1, 2, 1, 3, GTK_FILL, GTK_FILL, 2,4);
2563
2564         /* Category. */
2565         gtk_table_attach(GTK_TABLE(table),
2566                 label = gtk_label_new(_("Category")),
2567                 2, 3, 1, 2, GTK_FILL, 0, 2, 4);
2568         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2569         gtk_table_attach(GTK_TABLE(table),
2570                 cmb_category = poi_create_cat_combo(),
2571                 3, 4, 1, 2, GTK_FILL, 0, 2, 4);
2572
2573         /* Page. */
2574         gtk_table_attach(GTK_TABLE(table),
2575                 label = gtk_label_new(_("Page")),
2576                 2, 3, 2, 3, GTK_FILL, 0, 2, 4);
2577         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2578         gtk_table_attach(GTK_TABLE(table),
2579                 num_page = hildon_number_editor_new(1, 999),
2580                 3, 4, 2, 3, GTK_FILL, 0, 2, 4);
2581
2582
2583         /* Another table for the Origin and Query. */
2584         gtk_table_attach(GTK_TABLE(table),
2585                 table2 = gtk_table_new(2, 2, FALSE),
2586                 0, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2587
2588         /* Origin. */
2589         gtk_table_attach(GTK_TABLE(table2),
2590                 oti.rad_use_text = gtk_radio_button_new_with_label_from_widget(
2591                     GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")),
2592                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2593         gtk_table_attach(GTK_TABLE(table2),
2594                 oti.txt_origin = gtk_entry_new(),
2595                 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2596         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_origin), 25);
2597 #ifndef LEGACY
2598         g_object_set(G_OBJECT(oti.txt_origin), "hildon-input-mode",
2599                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2600 #else
2601         g_object_set(G_OBJECT(oti.txt_origin), HILDON_AUTOCAP, FALSE, NULL);
2602 #endif
2603
2604         /* Query. */
2605         gtk_table_attach(GTK_TABLE(table2),
2606                 label = gtk_label_new(_("Query")),
2607                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2608         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2609         gtk_table_attach(GTK_TABLE(table2),
2610                 oti.txt_query = gtk_entry_new(),
2611                 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2612         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_query), 25);
2613 #ifndef LEGACY
2614         g_object_set(G_OBJECT(oti.txt_query), "hildon-input-mode",
2615                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2616 #else
2617         g_object_set(G_OBJECT(oti.txt_query), HILDON_AUTOCAP, FALSE, NULL);
2618 #endif
2619
2620         /* Set up auto-completion. */
2621         origin_comp = gtk_entry_completion_new();
2622         gtk_entry_completion_set_model(origin_comp,GTK_TREE_MODEL(_loc_model));
2623         gtk_entry_completion_set_text_column(origin_comp, 0);
2624         gtk_entry_set_completion(GTK_ENTRY(oti.txt_origin), origin_comp);
2625
2626         g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled",
2627                           G_CALLBACK(origin_type_selected), &oti);
2628         g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled",
2629                           G_CALLBACK(origin_type_selected), &oti);
2630         g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled",
2631                           G_CALLBACK(origin_type_selected), &oti);
2632
2633         g_signal_connect(G_OBJECT(cmb_category), "changed",
2634                 G_CALLBACK(poi_download_cat_selected), oti.txt_query);
2635     }
2636
2637     /* Initialize fields. */
2638
2639     hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_page), 1);
2640
2641     gtk_entry_set_text(GTK_ENTRY(txt_source_url), _poi_dl_url);
2642     if(unity != 0)
2643     {
2644         gchar buffer[80];
2645         gchar strlat[32];
2646         gchar strlon[32];
2647         gdouble lat, lon;
2648
2649         unit2latlon(unitx, unity, lat, lon);
2650
2651         g_ascii_formatd(strlat, 32, "%.06f", lat);
2652         g_ascii_formatd(strlon, 32, "%.06f", lon);
2653         snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
2654
2655         gtk_entry_set_text(GTK_ENTRY(oti.txt_origin), buffer);
2656         gtk_toggle_button_set_active(
2657                 GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2658     }
2659     /* Else use "End of Route" by default if they have a route. */
2660     else if(_route.head != _route.tail)
2661     {
2662         /* There is no route, so make it the default. */
2663         gtk_widget_set_sensitive(oti.rad_use_route, TRUE);
2664         gtk_toggle_button_set_active(
2665                 GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
2666         gtk_widget_grab_focus(oti.rad_use_route);
2667     }
2668     /* Else use "GPS Location" if they have GPS enabled. */
2669     else
2670     {
2671         /* There is no route, so desensitize "Use End of Route." */
2672         gtk_widget_set_sensitive(oti.rad_use_route, FALSE);
2673         if(_enable_gps)
2674         {
2675             gtk_toggle_button_set_active(
2676                     GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
2677             gtk_widget_grab_focus(oti.rad_use_gps);
2678         }
2679         /* Else use text. */
2680         else
2681         {
2682             gtk_toggle_button_set_active(
2683                     GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2684             gtk_widget_grab_focus(oti.txt_origin);
2685         }
2686     }
2687
2688     gtk_widget_show_all(dialog);
2689
2690     while(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT)
2691     {
2692         gchar origin_buffer[BUFFER_SIZE];
2693         const gchar *source_url, *origin, *query;
2694         gchar *file_uri_str = NULL;
2695         gchar *bytes = NULL;
2696         gint size;
2697         GnomeVFSResult vfs_result;
2698         GList *poi_list = NULL;
2699
2700         source_url = gtk_entry_get_text(GTK_ENTRY(txt_source_url));
2701         if(!strlen(source_url))
2702         {
2703             popup_error(dialog, _("Please specify a source URL."));
2704             continue;
2705         }
2706         else
2707         {
2708             g_free(_poi_dl_url);
2709             _poi_dl_url = g_strdup(source_url);
2710         }
2711
2712         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)))
2713         {
2714             gchar strlat[32];
2715             gchar strlon[32];
2716             latlon2unit(_gps.lat, _gps.lon, unitx, unity);
2717             g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
2718             g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
2719             snprintf(origin_buffer, sizeof(origin_buffer),
2720                     "%s, %s", strlat, strlon);
2721             origin = origin_buffer;
2722         }
2723         else if(gtk_toggle_button_get_active(
2724                     GTK_TOGGLE_BUTTON(oti.rad_use_route)))
2725         {
2726             gchar strlat[32];
2727             gchar strlon[32];
2728             Point *p;
2729             gdouble lat, lon;
2730
2731             /* Use last non-zero route point. */
2732             for(p = _route.tail; !p->unity; p--) { }
2733
2734             unitx = p->unitx;
2735             unity = p->unity;
2736             unit2latlon(p->unitx, p->unity, lat, lon);
2737             g_ascii_formatd(strlat, 32, "%.06f", lat);
2738             g_ascii_formatd(strlon, 32, "%.06f", lon);
2739             snprintf(origin_buffer, sizeof(origin_buffer),
2740                     "%s, %s", strlat, strlon);
2741             origin = origin_buffer;
2742         }
2743         else
2744         {
2745             Point porig;
2746             origin = gtk_entry_get_text(GTK_ENTRY(oti.txt_origin));
2747             if(*origin)
2748             {
2749                 porig = locate_address(dialog, origin);
2750                 if(!porig.unity)
2751                     continue;
2752             }
2753         }
2754
2755         if(!*origin)
2756         {
2757             popup_error(dialog, _("Please specify an origin."));
2758             continue;
2759         }
2760
2761         if(gtk_combo_box_get_active(GTK_COMBO_BOX(cmb_category)) == -1)
2762         {
2763             popup_error(dialog, _("Please specify a default category."));
2764             continue;
2765         }
2766
2767         query = gtk_entry_get_text(GTK_ENTRY(oti.txt_query));
2768         if(!strlen(query))
2769         {
2770             popup_error(dialog, _("Please specify a query."));
2771             continue;
2772         }
2773
2774         /* Construct the URL. */
2775         {
2776             gchar *origin_escaped;
2777             gchar *query_escaped;
2778
2779             origin_escaped = gnome_vfs_escape_string(origin);
2780             query_escaped = gnome_vfs_escape_string(query);
2781             file_uri_str = g_strdup_printf(
2782                     source_url, origin_escaped, query_escaped,
2783                     hildon_number_editor_get_value(
2784                         HILDON_NUMBER_EDITOR(num_page)));
2785             g_free(origin_escaped);
2786             g_free(query_escaped);
2787         }
2788
2789         /* Parse the given file as GPX. */
2790         if(GNOME_VFS_OK != (vfs_result = gnome_vfs_read_entire_file(
2791                         file_uri_str, &size, &bytes)))
2792         {
2793             popup_error(dialog, gnome_vfs_result_to_string(vfs_result));
2794         }
2795         else if(strncmp(bytes, "<?xml", strlen("<?xml")))
2796         {
2797             /* Not an XML document - must be bad locations. */
2798             popup_error(dialog, _("Invalid origin or query."));
2799             printf("bytes: %s\n", bytes);
2800         }
2801         else if(gpx_poi_parse(bytes, size, &poi_list))
2802         {
2803             /* Insert the POIs into the database. */
2804             gint num_inserts = poi_list_insert(dialog, poi_list,
2805                     GTK_COMBO_BOX(cmb_category));
2806
2807             if(num_inserts)
2808             {
2809                 /* Create a new dialog with the results. */
2810                 poi_list_dialog(dialog, unitx, unity, poi_list);
2811             }
2812
2813             poi_list_free(poi_list);
2814         }
2815         else
2816             popup_error(dialog, _("Error parsing GPX file."));
2817
2818         g_free(file_uri_str);
2819         g_free(bytes);
2820
2821         /* Increment the page number for them. */
2822         hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(num_page),
2823             hildon_number_editor_get_value(HILDON_NUMBER_EDITOR(num_page)) +1);
2824     }
2825
2826     /* Hide the dialog. */
2827     gtk_widget_hide(dialog);
2828
2829     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
2830     return TRUE;
2831 }
2832
2833 gboolean
2834 poi_browse_dialog(gint unitx, gint unity)
2835 {
2836     static GtkWidget *dialog = NULL;
2837     static GtkWidget *table = NULL;
2838     static GtkWidget *table2 = NULL;
2839     static GtkWidget *label = NULL;
2840     static GtkWidget *cmb_category = NULL;
2841     static OriginToggleInfo oti;
2842     printf("%s()\n", __PRETTY_FUNCTION__);
2843
2844     if(!dialog)
2845     {
2846         GtkEntryCompletion *origin_comp;
2847
2848         dialog = gtk_dialog_new_with_buttons(_("Browse POIs"),
2849                 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
2850                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
2851                 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
2852                 NULL);
2853
2854         /* Enable the help button. */
2855 #ifndef LEGACY
2856         hildon_help_dialog_help_enable(
2857 #else
2858         ossohelp_dialog_help_enable(
2859 #endif
2860                 GTK_DIALOG(dialog), HELP_ID_BROWSEPOI, _osso);
2861
2862         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
2863                 table = gtk_table_new(3, 4, FALSE), TRUE, TRUE, 0);
2864
2865         /* Auto. */
2866         gtk_table_attach(GTK_TABLE(table),
2867                 oti.rad_use_gps = gtk_radio_button_new_with_label(NULL,
2868                     _("Use GPS Location")),
2869                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2870
2871         /* Use End of Route. */
2872         gtk_table_attach(GTK_TABLE(table),
2873                oti.rad_use_route = gtk_radio_button_new_with_label_from_widget(
2874                    GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")),
2875                0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2876
2877         gtk_table_attach(GTK_TABLE(table),
2878                 gtk_vseparator_new(),
2879                 1, 2, 0, 2, GTK_FILL, GTK_FILL, 2, 4);
2880
2881         /* Category. */
2882         gtk_table_attach(GTK_TABLE(table),
2883                 label = gtk_label_new(_("Category")),
2884                 2, 3, 0, 1, GTK_FILL, 0, 2, 4);
2885         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2886         gtk_table_attach(GTK_TABLE(table),
2887                 cmb_category = poi_create_cat_combo(),
2888                 3, 4, 0, 1, GTK_FILL, 0, 2, 4);
2889         /* Add an extra, "<any>" category. */
2890         {
2891             GtkTreeIter iter;
2892             GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(
2893                         GTK_COMBO_BOX(cmb_category)));
2894             gtk_list_store_prepend(store, &iter);
2895             gtk_list_store_set(store, &iter, 0, -1, 1, "<any>", -1);
2896             gtk_combo_box_set_active_iter(GTK_COMBO_BOX(cmb_category), &iter);
2897         }
2898
2899
2900         /* Another table for the Origin and Query. */
2901         gtk_table_attach(GTK_TABLE(table),
2902                 table2 = gtk_table_new(2, 2, FALSE),
2903                 0, 4, 2, 3, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2904
2905         /* Origin. */
2906         gtk_table_attach(GTK_TABLE(table2),
2907                 oti.rad_use_text = gtk_radio_button_new_with_label_from_widget(
2908                     GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")),
2909                 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
2910         gtk_table_attach(GTK_TABLE(table2),
2911                 oti.txt_origin = gtk_entry_new(),
2912                 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2913         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_origin), 25);
2914 #ifndef LEGACY
2915         g_object_set(G_OBJECT(oti.txt_origin), "hildon-input-mode",
2916                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2917 #else
2918         g_object_set(G_OBJECT(oti.txt_origin), HILDON_AUTOCAP, FALSE, NULL);
2919 #endif
2920
2921         /* Destination. */
2922         gtk_table_attach(GTK_TABLE(table2),
2923                 label = gtk_label_new(_("Query")),
2924                 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
2925         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
2926         gtk_table_attach(GTK_TABLE(table2),
2927                 oti.txt_query = gtk_entry_new(),
2928                 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
2929         gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_query), 25);
2930 #ifndef LEGACY
2931         g_object_set(G_OBJECT(oti.txt_query), "hildon-input-mode",
2932                 HILDON_GTK_INPUT_MODE_FULL, NULL);
2933 #else
2934         g_object_set(G_OBJECT(oti.txt_query), HILDON_AUTOCAP, FALSE, NULL);
2935 #endif
2936
2937         /* Set up auto-completion. */
2938         origin_comp = gtk_entry_completion_new();
2939         gtk_entry_completion_set_model(origin_comp,GTK_TREE_MODEL(_loc_model));
2940         gtk_entry_completion_set_text_column(origin_comp, 0);
2941         gtk_entry_set_completion(GTK_ENTRY(oti.txt_origin), origin_comp);
2942
2943         g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled",
2944                           G_CALLBACK(origin_type_selected), &oti);
2945         g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled",
2946                           G_CALLBACK(origin_type_selected), &oti);
2947         g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled",
2948                           G_CALLBACK(origin_type_selected), &oti);
2949     }
2950
2951     /* Initialize fields. */
2952
2953     if(unity != 0)
2954     {
2955         gchar buffer[80];
2956         gchar strlat[32];
2957         gchar strlon[32];
2958         gdouble lat, lon;
2959
2960         unit2latlon(unitx, unity, lat, lon);
2961
2962         g_ascii_formatd(strlat, 32, "%.06f", lat);
2963         g_ascii_formatd(strlon, 32, "%.06f", lon);
2964         snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
2965
2966         gtk_entry_set_text(GTK_ENTRY(oti.txt_origin), buffer);
2967         gtk_toggle_button_set_active(
2968                 GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2969     }
2970     /* Else use "End of Route" by default if they have a route. */
2971     else if(_route.head != _route.tail)
2972     {
2973         /* There is no route, so make it the default. */
2974         gtk_widget_set_sensitive(oti.rad_use_route, TRUE);
2975         gtk_toggle_button_set_active(
2976                 GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
2977         gtk_widget_grab_focus(oti.rad_use_route);
2978     }
2979     /* Else use "GPS Location" if they have GPS enabled. */
2980     else
2981     {
2982         /* There is no route, so desensitize "Use End of Route." */
2983         gtk_widget_set_sensitive(oti.rad_use_route, FALSE);
2984         if(_enable_gps)
2985         {
2986             gtk_toggle_button_set_active(
2987                     GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
2988             gtk_widget_grab_focus(oti.rad_use_gps);
2989         }
2990         /* Else use text. */
2991         else
2992         {
2993             gtk_toggle_button_set_active(
2994                     GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
2995             gtk_widget_grab_focus(oti.txt_origin);
2996         }
2997     }
2998
2999     gtk_widget_show_all(dialog);
3000
3001     while(gtk_dialog_run(GTK_DIALOG(dialog)) ==GTK_RESPONSE_ACCEPT)
3002     {
3003         gchar buffer[BUFFER_SIZE];
3004         const gchar *origin, *query;
3005         gdouble lat, lon;
3006         GList *poi_list = NULL;
3007         gint cat_id;
3008         gboolean is_cat = FALSE;
3009         sqlite3_stmt *stmt;
3010
3011         if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)))
3012         {
3013             gchar strlat[32];
3014             gchar strlon[32];
3015             latlon2unit(_gps.lat, _gps.lon, unitx, unity);
3016             g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
3017             g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
3018             snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
3019             origin = buffer;
3020         }
3021         else if(gtk_toggle_button_get_active(
3022                     GTK_TOGGLE_BUTTON(oti.rad_use_route)))
3023         {
3024             gchar strlat[32];
3025             gchar strlon[32];
3026             Point *p;
3027             gdouble lat, lon;
3028
3029             /* Use last non-zero route point. */
3030             for(p = _route.tail; !p->unity; p--) { }
3031
3032             unitx = p->unitx;
3033             unity = p->unity;
3034             unit2latlon(p->unitx, p->unity, lat, lon);
3035             g_ascii_formatd(strlat, 32, "%.06f", lat);
3036             g_ascii_formatd(strlon, 32, "%.06f", lon);
3037             snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
3038             origin = buffer;
3039         }
3040         else
3041         {
3042             Point porig;
3043             origin = gtk_entry_get_text(GTK_ENTRY(oti.txt_origin));
3044             porig = locate_address(dialog, origin);
3045             if(!porig.unity)
3046                 continue;
3047         }
3048
3049         if(!strlen(origin))
3050         {
3051             popup_error(dialog, _("Please specify an origin."));
3052             continue;
3053         }
3054
3055         /* Check if we're doing a category search. */
3056         {
3057             GtkTreeIter iter;
3058             if(gtk_combo_box_get_active_iter(
3059                     GTK_COMBO_BOX(cmb_category), &iter))
3060             {
3061                 gtk_tree_model_get(
3062                         gtk_combo_box_get_model(GTK_COMBO_BOX(cmb_category)),
3063                         &iter, 0, &cat_id, -1);
3064                 if(cat_id >= 0)
3065                 {
3066                     is_cat = TRUE;
3067                 }
3068             }
3069         }
3070
3071         query = g_strdup_printf("%%%s%%",
3072                 gtk_entry_get_text(GTK_ENTRY(oti.txt_query)));
3073
3074         unit2latlon(unitx, unity, lat, lon);
3075
3076         if(is_cat)
3077         {
3078             if(SQLITE_OK != sqlite3_bind_int(_stmt_browsecat_poi, 1, cat_id) ||
3079                SQLITE_OK != sqlite3_bind_text(_stmt_browsecat_poi, 2, query,
3080                    -1, g_free) ||
3081                SQLITE_OK != sqlite3_bind_double(_stmt_browsecat_poi, 3, lat) ||
3082                SQLITE_OK != sqlite3_bind_double(_stmt_browsecat_poi, 4, lon))
3083             {
3084                 g_printerr("Failed to bind values for _stmt_browsecat_poi\n");
3085                 continue;
3086             }
3087             stmt = _stmt_browsecat_poi;
3088         }
3089         else
3090         {
3091             if(SQLITE_OK != sqlite3_bind_text(_stmt_browse_poi, 1, query,
3092                         -1, g_free) ||
3093                SQLITE_OK != sqlite3_bind_double(_stmt_browse_poi, 2, lat) ||
3094                SQLITE_OK != sqlite3_bind_double(_stmt_browse_poi, 3, lon))
3095             {
3096                 g_printerr("Failed to bind values for _stmt_browse_poi\n");
3097                 continue;
3098             }
3099             stmt = _stmt_browse_poi;
3100         }
3101
3102         while(SQLITE_ROW == sqlite3_step(stmt))
3103         {
3104             PoiInfo *poi = g_slice_new(PoiInfo);
3105             poi->poi_id = sqlite3_column_int(stmt, 0);
3106             poi->cat_id = sqlite3_column_int(stmt, 1);
3107             poi->lat = sqlite3_column_double(stmt, 2);
3108             poi->lon = sqlite3_column_double(stmt, 3);
3109             poi->label =g_strdup(sqlite3_column_text(stmt, 4));
3110             poi->desc = g_strdup(sqlite3_column_text(stmt, 5));
3111             poi->clabel=g_strdup(sqlite3_column_text(stmt, 6));
3112             poi_list = g_list_prepend(poi_list, poi);
3113         }
3114         sqlite3_reset(stmt);
3115
3116         if(poi_list)
3117         {
3118             /* Create a new dialog with the results. */
3119             poi_list_dialog(dialog, unitx, unity, poi_list);
3120             poi_list_free(poi_list);
3121         }
3122         else
3123             popup_error(dialog, _("No POIs found."));
3124     }
3125
3126     map_force_redraw();
3127
3128     /* Hide the dialog. */
3129     gtk_widget_hide(dialog);
3130
3131     vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
3132     return TRUE;
3133 }
3134
3135 /**
3136  * Render all the POI data.  This should be done before rendering track data.
3137  */
3138 void
3139 map_render_poi()
3140 {
3141     gint unitx, unity;
3142     gdouble lat1, lat2, lon1, lon2;
3143     gchar buffer[100];
3144     gint poix, poiy;
3145     GdkPixbuf *pixbuf = NULL;
3146     GError *error = NULL;
3147     printf("%s()\n", __PRETTY_FUNCTION__);
3148
3149     if(_poi_db && _poi_zoom > _zoom)
3150     {
3151         gint diag_offset = pixel2unit(MAX(_view_width_pixels,
3152                     _view_height_pixels) / 2);
3153         buf2unit(0, _view_height_pixels, unitx, unity);
3154         unitx = _center.unitx - diag_offset;
3155         unity = _center.unity + diag_offset;
3156         unit2latlon(unitx, unity, lat1, lon1);
3157         unitx = _center.unitx + diag_offset;
3158         unity = _center.unity - diag_offset;
3159         unit2latlon(unitx, unity, lat2, lon2);
3160
3161         if(SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 1, lat1) ||
3162            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 2, lat2) ||
3163            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 3, lon1) ||
3164            SQLITE_OK != sqlite3_bind_double(_stmt_select_poi, 4, lon2))
3165         {
3166             g_printerr("Failed to bind values for _stmt_select_poi\n");
3167             return;
3168         }
3169
3170         while(SQLITE_ROW == sqlite3_step(_stmt_select_poi))
3171         {
3172             lat1 = sqlite3_column_double(_stmt_select_poi, 0);
3173             lon1 = sqlite3_column_double(_stmt_select_poi, 1);
3174             gchar *poi_label = g_utf8_strdown(sqlite3_column_text(
3175                     _stmt_select_poi, 3), -1);
3176             gchar *cat_label = g_utf8_strdown(sqlite3_column_text(
3177                     _stmt_select_poi, 6), -1);
3178
3179             latlon2unit(lat1, lon1, unitx, unity);
3180             unit2buf(unitx, unity, poix, poiy);
3181
3182             /* Try to get icon for specific POI first. */
3183             snprintf(buffer, sizeof(buffer), "%s/%s.jpg",
3184                     _poi_db_dirname, poi_label);
3185             pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3186             if(error)
3187             {
3188                 /* No icon for specific POI - try for category. */
3189                 error = NULL;
3190                 snprintf(buffer, sizeof(buffer), "%s/%s.jpg",
3191                         _poi_db_dirname, cat_label);
3192                 pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3193             }
3194             if(error)
3195             {
3196                 /* No icon for POI or for category.
3197                  * Try default POI icon file. */
3198                 error = NULL;
3199                 snprintf(buffer, sizeof(buffer), "%s/poi.jpg",
3200                         _poi_db_dirname);
3201                 pixbuf = gdk_pixbuf_new_from_file(buffer, &error);
3202             }
3203             if(error)
3204             {
3205                 /* No icon for POI or for category or default POI icon file.
3206                    Draw default purple square. */
3207                 error = NULL;
3208                 gdk_draw_rectangle(_map_pixmap, _gc[COLORABLE_POI], TRUE,
3209                         poix - (gint)(1.5f * _draw_width),
3210                         poiy - (gint)(1.5f * _draw_width),
3211                         3 * _draw_width,
3212                         3 * _draw_width);
3213             }
3214             else
3215             {
3216                 /* We found an icon to draw. */
3217                 gdk_draw_pixbuf(
3218                         _map_pixmap,
3219                         _gc[COLORABLE_POI],
3220                         pixbuf,
3221                         0, 0,
3222                         poix - gdk_pixbuf_get_width(pixbuf) / 2,
3223                         poiy - gdk_pixbuf_get_height(pixbuf) / 2,
3224                         -1,-1,
3225                         GDK_RGB_DITHER_NONE, 0, 0);
3226                 g_object_unref(pixbuf);
3227             }
3228
3229             g_free(poi_label);
3230             g_free(cat_label);
3231         }
3232         sqlite3_reset(_stmt_select_poi);
3233     }
3234
3235     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3236 }
3237
3238 void
3239 poi_destroy()
3240 {
3241     printf("%s()\n", __PRETTY_FUNCTION__);
3242
3243     if(_poi_db) 
3244     { 
3245         sqlite3_close(_poi_db); 
3246         _poi_db = NULL; 
3247     }
3248
3249     vprintf("%s(): return\n", __PRETTY_FUNCTION__);
3250 }