]> err.no Git - mapper/blob - src/search.c
Don't destroy dialog
[mapper] / src / search.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  * Copyright (C) 2006-2007 John Costigan.
6  *
7  * POI and GPS-Info code originally written by Cezary Jackiewicz.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  */
24
25 #include <config.h>
26
27 #define _GNU_SOURCE
28
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <strings.h>
33 #include <stddef.h>
34 #include <locale.h>
35 #include <math.h>
36 #include <errno.h>
37 #include <sys/wait.h>
38 #include <glib/gstdio.h>
39 #include <gtk/gtk.h>
40 #include <fcntl.h>
41 #include <libintl.h>
42 #include <locale.h>
43
44 #include "utils.h"
45 #include "poi.h"
46 #include "gps.h"
47 #include "map.h"
48 #include "mapper-types.h"
49 #include "ui-common.h"
50 #include "settings.h"
51 #include "poi-gui.h"
52 #include "osm.h"
53 #include "help.h"
54 #include "osm-db.h"
55 #include "search.h"
56
57 typedef struct _search_query poi_search_query;
58 struct _search_query {
59         gdouble lat;
60         gdouble lon;
61         guint cat_id;
62         gchar *query;
63 };
64
65 typedef struct _search_dialog search_dialog;
66 struct _search_dialog {
67         GtkWidget *dialog;
68         GtkWidget *cmb_type;
69         GtkWidget *cmb_category;
70         GtkWidget *list;
71         GtkWidget *search_entry;
72         GtkWidget *label;
73         GtkListStore *store;
74         gdouble lat;
75         gdouble lon;
76         mapper_search_type stype;
77 };
78
79 static search_dialog sd;
80
81 static gboolean
82 search_do_cb(GtkWidget *widget, gpointer data)
83 {
84 gchar *st;
85 guint cid;
86 GtkTreeIter iter;
87 guint slen;
88 search_dialog *s=(search_dialog *)data;
89 gboolean sres=FALSE;
90 slen=strlen(gtk_entry_get_text(GTK_ENTRY(s->search_entry)));
91
92 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(s->cmb_category), &iter)==TRUE)
93         gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(s->cmb_category)), &iter, 0, &cid, -1);
94 else
95         cid=-1;
96 if (s->stype==SEARCH_TYPE_POI && cid==-1 && slen<2) {
97         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
98         return TRUE;
99 } else if (slen<2 && s->stype!=SEARCH_TYPE_POI) {
100         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
101         return TRUE;
102 }
103
104 st=g_strdup(gtk_entry_get_text(GTK_ENTRY(s->search_entry)));
105
106 switch (s->stype) {
107         case SEARCH_TYPE_POI:
108                 sres=poi_search((cid==-1 && slen>0) ? POI_SEARCH_TEXT : (cid!=-1 && slen==0) ? POI_SEARCH_CAT : POI_SEARCH_TEXT_CAT, s->lat, s->lon, st, cid, &s->store);
109         break;
110         case SEARCH_TYPE_WAY:
111                 sres=osm_way_search(s->lat, s->lon, st, &s->store);
112         break;
113         case SEARCH_TYPE_PLACE:
114                 popup_error(s->dialog, "Not yet implemented");
115                 sres=FALSE;
116         break;
117 }
118
119 if (sres==TRUE) {
120         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
121         g_object_unref(G_OBJECT(s->store));
122 } else {
123         s->store=NULL;
124         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
125 }
126
127 g_free(st);
128 return TRUE;
129 }
130
131 static gboolean
132 search_get_list_item_latlon(GtkWidget *list, gdouble *lat, gdouble *lon)
133 {
134 GtkTreeIter iter;
135 GtkTreeModel *model;
136
137 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
138         return FALSE;
139
140 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
141 if (!model)
142         return FALSE;
143
144 gtk_tree_model_get(model, &iter, ITEM_LAT, lat, -1);
145 gtk_tree_model_get(model, &iter, ITEM_LON, lon, -1);
146 return TRUE;
147 }
148
149 static guint
150 search_get_list_item_id(GtkWidget *list)
151 {
152 guint id;
153 GtkTreeIter iter;
154 GtkTreeModel *model;
155
156 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
157         return 0;
158
159 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
160 if (!model)
161         return 0;
162
163 gtk_tree_model_get(model, &iter, ITEM_ID, &id, -1);
164 return id;
165 }
166
167 static void
168 search_set_dialog_mode(search_dialog *s)
169 {
170 s->stype=gtk_combo_box_get_active(GTK_COMBO_BOX(s->cmb_type));
171 switch (s->stype) {
172         case SEARCH_TYPE_POI:
173                 gtk_widget_show(s->cmb_category);
174         break;
175         case SEARCH_TYPE_WAY:
176         case SEARCH_TYPE_PLACE:
177                 gtk_widget_hide(s->cmb_category);
178         break;
179         default:
180                 g_assert_not_reached();
181         break;
182 }
183 }
184
185 static gboolean
186 search_type_changed_cb(GtkWidget *widget, gpointer data)
187 {
188 search_dialog *s=(search_dialog *)data;
189 search_set_dialog_mode(s);
190 if (s->store)
191         gtk_list_store_clear(s->store);
192 s->store=NULL;
193 gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
194 return TRUE;
195 }
196
197 static void
198 search_item_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
199 {
200 search_dialog *s=(search_dialog *)data;
201 gdouble lat, lon;
202 GtkTreeIter iter;
203 GtkTreeModel *model;
204 guint id;
205
206 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)), NULL, &iter))
207         return;
208
209 model=gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); 
210 if (!model)
211         return;
212
213 gtk_tree_model_get(model, &iter, ITEM_LAT, &lat, -1);
214 gtk_tree_model_get(model, &iter, ITEM_LON, &lon, -1);
215
216 map_center_latlon(lat, lon);
217 map_update_location_from_center();
218 #if 0
219 gtk_widget_destroy(s->dialog);
220 #endif
221 }
222
223 gboolean
224 mapper_search_dialog(mapper_search_type stype, gdouble lat, gdouble lon)
225 {
226 GtkWidget *sw, *hbox, *label, *btn_search;
227 GtkTreeViewColumn *column;
228 GtkCellRenderer *renderer;
229 gint res;
230
231 sd.store=NULL;
232 sd.lat=lat;
233 sd.lon=lon;
234 sd.stype=stype;
235
236 sd.dialog = gtk_dialog_new_with_buttons(_("Search"),
237                         GTK_WINDOW(_window),
238                         GTK_DIALOG_MODAL,
239                         _("Goto"), 1,
240                         _("Route to"), 2,
241                         _("Edit"), 3,
242                         GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT, 
243                         NULL);
244
245 gtk_window_set_default_size(GTK_WINDOW(sd.dialog), 500, 300);
246
247 hbox = gtk_hbox_new(FALSE, 4),
248 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), hbox, FALSE, FALSE, 0);
249
250 label=gtk_label_new(_("Search:"));
251 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
252
253 sd.cmb_type=gtk_combo_box_new_text();
254 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "POI");
255 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Street");
256 #if 0
257 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Place");
258 #endif
259 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_type, FALSE, FALSE, 0);
260
261 sd.cmb_category = category_combo_new();
262 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_category, FALSE, FALSE, 0);
263 poi_category_combo_populate(sd.cmb_category, 0, TRUE);
264
265 sd.search_entry=gtk_entry_new();
266 gtk_box_pack_start(GTK_BOX(hbox), sd.search_entry, TRUE, TRUE, 0);
267
268 btn_search=gtk_button_new_with_label(_("Search"));
269 gtk_box_pack_start(GTK_BOX(hbox), btn_search, FALSE, FALSE, 0);
270
271 sw = gtk_scrolled_window_new(NULL, NULL);
272 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
273 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
274 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), sw, TRUE, TRUE, 0);
275
276 sd.list=gtk_tree_view_new();
277 gtk_tree_selection_set_mode(gtk_tree_view_get_selection (GTK_TREE_VIEW(sd.list)), GTK_SELECTION_SINGLE);
278 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(sd.list), TRUE);
279 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(sd.list), TRUE);
280
281 renderer = gtk_cell_renderer_text_new();
282 column = gtk_tree_view_column_new_with_attributes(_("Location"), renderer, "text", ITEM_LATLON, NULL);
283 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
284
285 renderer = gtk_cell_renderer_text_new();
286 column = gtk_tree_view_column_new_with_attributes(_("Distance"), renderer, "text", ITEM_DIST, NULL);
287 gtk_tree_view_column_set_sort_column_id (column, ITEM_DIST);
288 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
289
290 renderer = gtk_cell_renderer_text_new();
291 column = gtk_tree_view_column_new_with_attributes(_("Label"), renderer, "text", ITEM_LABEL, NULL);
292 gtk_tree_view_column_set_sort_column_id (column, ITEM_LABEL);
293 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
294
295 renderer = gtk_cell_renderer_text_new();
296 column = gtk_tree_view_column_new_with_attributes(_("Category"), renderer, "text", ITEM_CATLAB, NULL);
297 gtk_tree_view_column_set_sort_column_id (column, ITEM_CATLAB);
298 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
299
300 gtk_tree_view_set_search_column (GTK_TREE_VIEW(sd.list), ITEM_LABEL);
301 gtk_container_add(GTK_CONTAINER(sw), sd.list);
302
303 sd.label=gtk_label_new("");
304 gtk_box_pack_start(GTK_BOX(hbox), sd.label, FALSE, FALSE, 0);
305
306 g_signal_connect(G_OBJECT(btn_search), "clicked", G_CALLBACK(search_do_cb), &sd);
307 g_signal_connect(G_OBJECT(sd.cmb_type), "changed", G_CALLBACK(search_type_changed_cb), &sd);
308 g_signal_connect(G_OBJECT(sd.list), "row-activated", G_CALLBACK(search_item_activated_cb), &sd);
309
310 gtk_widget_show_all(sd.dialog);
311 gtk_combo_box_set_active(GTK_COMBO_BOX(sd.cmb_type), sd.stype);
312 search_set_dialog_mode(&sd);
313
314 while ((res=gtk_dialog_run(GTK_DIALOG(sd.dialog)))!=GTK_RESPONSE_REJECT) {
315         gdouble lat, lon;
316
317         switch (res) {
318         case 1:
319                 if (search_get_list_item_latlon(sd.list, &lat, &lon)==FALSE) {
320                         popup_error(sd.dialog, _("Select a location from the list."));
321                 } else {
322                         map_center_latlon(lat, lon);
323                         map_update_location_from_center();
324                 }
325                 continue;
326         break;
327         case 2:
328                 if (search_get_list_item_latlon(sd.list, &_dest.lat, &_dest.lon)==FALSE) {
329                         popup_error(sd.dialog, _("Select a location from the list."));
330                 } else {
331                         _dest.valid=TRUE;
332                         map_update_location_from_center();
333                 }
334                 continue;
335         break;
336         case 3:
337                 switch (sd.stype) {
338                         case SEARCH_TYPE_POI: {
339                                 poi_info *p=NULL;
340                                 guint id;
341                 
342                                 id=search_get_list_item_id(sd.list);
343                                 if (id>0) {
344                                         p=poi_get_by_id(id);
345                                         if (p) {
346                                                 gtk_widget_destroy(sd.dialog);
347                                                 poi_edit_dialog(ACTION_EDIT_POI, p);
348                                                 return TRUE; /* XXX: for now, this is not nice.. */
349                                         } else {
350                                                 popup_error(sd.dialog, _("Failed to fetch POI for editing."));
351                                         }
352                                 }
353                         }
354                         break;
355                         default:
356                                 popup_error(sd.dialog, _("Only POIs can be modified."));
357                         break;
358                 }
359                 continue;
360         break;
361         default:
362                 break;
363         break;
364         }
365 }
366
367 gtk_widget_destroy(sd.dialog);
368 return TRUE;
369 }
370