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