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