]> err.no Git - mapper/blob - src/search.c
Move some variables around
[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 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <stddef.h>
32 #include <locale.h>
33 #include <math.h>
34 #include <errno.h>
35 #include <sys/wait.h>
36 #include <glib/gstdio.h>
37 #include <gtk/gtk.h>
38 #include <fcntl.h>
39 #include <libintl.h>
40 #include <locale.h>
41
42 #include "utils.h"
43 #include "poi.h"
44 #include "gps.h"
45 #include "map.h"
46 #include "mapper-types.h"
47 #include "ui-common.h"
48 #include "settings.h"
49 #include "poi-gui.h"
50 #include "osm.h"
51 #include "help.h"
52 #include "osm-db.h"
53 #include "search.h"
54 #include "dialogs.h"
55
56 typedef struct _search_dialog search_dialog;
57 struct _search_dialog {
58         GtkWidget *dialog;
59         GtkWidget *cmb_type;
60         GtkWidget *cmb_category;
61         GtkWidget *list;
62         GtkWidget *search_entry;
63         GtkWidget *label;
64         GtkListStore *store;
65         gdouble lat;
66         gdouble lon;
67         mapper_search_type stype;
68 };
69
70 static search_dialog sd;
71 static GtkListStore *search_model=NULL;
72
73 static gboolean
74 search_do_cb(GtkWidget *widget, gpointer data)
75 {
76 gchar *st;
77 guint cid;
78 GtkTreeIter iter;
79 guint slen;
80 search_dialog *s=(search_dialog *)data;
81 gboolean sres=FALSE;
82 slen=strlen(gtk_entry_get_text(GTK_ENTRY(s->search_entry)));
83
84 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(s->cmb_category), &iter)==TRUE)
85         gtk_tree_model_get(gtk_combo_box_get_model(GTK_COMBO_BOX(s->cmb_category)), &iter, 0, &cid, -1);
86 else
87         cid=-1;
88 if (s->stype==SEARCH_TYPE_POI && cid==-1 && slen<2) {
89 #ifdef WITH_HILDON
90         hildon_banner_show_information(s->dialog, NULL, _("Query string too short. Minimum 2 characters."));
91 #else
92         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
93 #endif
94         return TRUE;
95 } else if (slen<2 && s->stype!=SEARCH_TYPE_POI) {
96 #ifdef WITH_HILDON
97         hildon_banner_show_information(s->dialog, NULL, _("Query string too short. Minimum 2 characters."));
98 #else
99         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
100 #endif
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                 MACRO_BANNER_SHOW_INFO(s->dialog, _("Searching POIs..."));
109                 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);
110         break;
111         case SEARCH_TYPE_WAY:
112                 MACRO_BANNER_SHOW_INFO(s->dialog, _("Searching streets..."));
113                 sres=osm_way_search(s->lat, s->lon, st, &s->store);
114         break;
115         case SEARCH_TYPE_PLACE:
116                 sres=osm_place_search(s->lat, s->lon, st, &s->store);
117         break;
118 }
119
120 if (sres==TRUE) {
121         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
122         g_object_unref(G_OBJECT(s->store));
123 } else {
124         s->store=NULL;
125         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
126 }
127
128 g_free(st);
129 return TRUE;
130 }
131
132 static gboolean
133 search_get_list_item_latlon(GtkWidget *list, gdouble *lat, gdouble *lon)
134 {
135 GtkTreeIter iter;
136 GtkTreeModel *model;
137
138 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
139         return FALSE;
140
141 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
142 if (!model)
143         return FALSE;
144
145 gtk_tree_model_get(model, &iter, ITEM_LAT, lat, -1);
146 gtk_tree_model_get(model, &iter, ITEM_LON, lon, -1);
147 return TRUE;
148 }
149
150 static guint
151 search_get_list_item_id(GtkWidget *list)
152 {
153 guint id;
154 GtkTreeIter iter;
155 GtkTreeModel *model;
156
157 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
158         return 0;
159
160 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
161 if (!model)
162         return 0;
163
164 gtk_tree_model_get(model, &iter, ITEM_ID, &id, -1);
165 return id;
166 }
167
168 static void
169 search_set_dialog_mode(search_dialog *s)
170 {
171 s->stype=gtk_combo_box_get_active(GTK_COMBO_BOX(s->cmb_type));
172 switch (s->stype) {
173         case SEARCH_TYPE_POI:
174                 gtk_widget_show(s->cmb_category);
175         break;
176         case SEARCH_TYPE_WAY:
177         case SEARCH_TYPE_PLACE:
178                 gtk_widget_hide(s->cmb_category);
179         break;
180         default:
181                 g_assert_not_reached();
182         break;
183 }
184 }
185
186 static gboolean
187 search_type_changed_cb(GtkWidget *widget, gpointer data)
188 {
189 search_dialog *s=(search_dialog *)data;
190 search_set_dialog_mode(s);
191 if (s->store)
192         gtk_list_store_clear(s->store);
193 s->store=NULL;
194 gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
195 return TRUE;
196 }
197
198 static void
199 search_item_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
200 {
201 search_dialog *s=(search_dialog *)data;
202 gdouble lat, lon;
203 GtkTreeIter iter;
204 GtkTreeModel *model;
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 g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
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 GtkEntryCompletion *search_comp;
230 gint res;
231
232 sd.store=NULL;
233 sd.lat=lat;
234 sd.lon=lon;
235 sd.stype=stype;
236
237 sd.dialog = gtk_dialog_new_with_buttons(_("Search"),
238                         GTK_WINDOW(_window),
239                         GTK_DIALOG_MODAL,
240                         _("Goto"), 1,
241                         _("Route to"), 2,
242                         _("Edit"), 3,
243                         GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT, 
244                         NULL);
245
246 if (search_model==NULL)
247         search_model=gtk_list_store_new(1, G_TYPE_STRING);
248
249 gtk_window_set_default_size(GTK_WINDOW(sd.dialog), 500, 300);
250
251 hbox = gtk_hbox_new(FALSE, 4),
252 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), hbox, FALSE, FALSE, 0);
253
254 label=gtk_label_new(_("Search:"));
255 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
256
257 sd.cmb_type=gtk_combo_box_new_text();
258 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "POI");
259 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Street");
260 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Place");
261 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_type, FALSE, FALSE, 0);
262
263 sd.cmb_category = category_combo_new();
264 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_category, FALSE, FALSE, 0);
265 poi_category_combo_populate(sd.cmb_category, 0, TRUE);
266
267 sd.search_entry=gtk_entry_new();
268 search_comp=gtk_entry_completion_new();
269 gtk_entry_completion_set_model(search_comp, GTK_TREE_MODEL(search_model));
270 gtk_entry_completion_set_text_column(search_comp, 0);
271 gtk_entry_set_completion(GTK_ENTRY(sd.search_entry), search_comp);
272 gtk_box_pack_start(GTK_BOX(hbox), sd.search_entry, TRUE, TRUE, 0);
273
274 btn_search=gtk_button_new_with_label(_("Search"));
275 gtk_box_pack_start(GTK_BOX(hbox), btn_search, FALSE, FALSE, 0);
276
277 sw = gtk_scrolled_window_new(NULL, NULL);
278 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
279 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
280 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), sw, TRUE, TRUE, 0);
281
282 sd.list=gtk_tree_view_new();
283 gtk_tree_selection_set_mode(gtk_tree_view_get_selection (GTK_TREE_VIEW(sd.list)), GTK_SELECTION_SINGLE);
284 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(sd.list), TRUE);
285 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(sd.list), TRUE);
286
287 renderer = gtk_cell_renderer_text_new();
288 column = gtk_tree_view_column_new_with_attributes(_("Location"), renderer, "text", ITEM_LATLON, NULL);
289 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
290
291 renderer = gtk_cell_renderer_text_new();
292 column = gtk_tree_view_column_new_with_attributes(_("Distance"), renderer, "text", ITEM_DIST, NULL);
293 gtk_tree_view_column_set_sort_column_id (column, ITEM_DIST);
294 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
295
296 renderer = gtk_cell_renderer_text_new();
297 column = gtk_tree_view_column_new_with_attributes(_("Label"), renderer, "text", ITEM_LABEL, NULL);
298 gtk_tree_view_column_set_sort_column_id (column, ITEM_LABEL);
299 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
300
301 renderer = gtk_cell_renderer_text_new();
302 column = gtk_tree_view_column_new_with_attributes(_("Category"), renderer, "text", ITEM_CATLAB, NULL);
303 gtk_tree_view_column_set_sort_column_id (column, ITEM_CATLAB);
304 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
305
306 gtk_tree_view_set_search_column (GTK_TREE_VIEW(sd.list), ITEM_LABEL);
307 gtk_container_add(GTK_CONTAINER(sw), sd.list);
308
309 sd.label=gtk_label_new("");
310 gtk_box_pack_start(GTK_BOX(hbox), sd.label, FALSE, FALSE, 0);
311
312 g_signal_connect(G_OBJECT(btn_search), "clicked", G_CALLBACK(search_do_cb), &sd);
313 g_signal_connect(G_OBJECT(sd.cmb_type), "changed", G_CALLBACK(search_type_changed_cb), &sd);
314 g_signal_connect(G_OBJECT(sd.list), "row-activated", G_CALLBACK(search_item_activated_cb), &sd);
315
316 gtk_widget_show_all(sd.dialog);
317 gtk_combo_box_set_active(GTK_COMBO_BOX(sd.cmb_type), sd.stype);
318 search_set_dialog_mode(&sd);
319
320 while ((res=gtk_dialog_run(GTK_DIALOG(sd.dialog)))!=GTK_RESPONSE_REJECT) {
321         gdouble lat, lon;
322
323         switch (res) {
324         case 1:
325                 if (search_get_list_item_latlon(sd.list, &lat, &lon)==FALSE) {
326                         popup_error(sd.dialog, _("Select a location from the list."));
327                 } else {
328                         map_center_latlon(lat, lon);
329                         g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
330                 }
331                 continue;
332         break;
333         case 2:
334                 if (search_get_list_item_latlon(sd.list, &_dest.lat, &_dest.lon)==FALSE) {
335                         popup_error(sd.dialog, _("Select a location from the list."));
336                 } else {
337                         _dest.valid=TRUE;
338                         g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
339                 }
340                 continue;
341         break;
342         case 3:
343                 switch (sd.stype) {
344                         case SEARCH_TYPE_POI: {
345                                 poi_info *p=NULL;
346                                 guint id;
347                 
348                                 id=search_get_list_item_id(sd.list);
349                                 if (id>0) {
350                                         p=poi_get_by_id(id);
351                                         if (p) {
352                                                 gtk_widget_destroy(sd.dialog);
353                                                 poi_edit_dialog(ACTION_EDIT_POI, p);
354                                                 return TRUE; /* XXX: for now, this is not nice.. */
355                                         } else {
356                                                 popup_error(sd.dialog, _("Failed to fetch POI for editing."));
357                                         }
358                                 }
359                         }
360                         break;
361                         default:
362                                 popup_error(sd.dialog, _("Only POIs can be modified."));
363                         break;
364                 }
365                 continue;
366         break;
367         default:
368                 break;
369         break;
370         }
371 }
372
373 gtk_widget_destroy(sd.dialog);
374 return TRUE;
375 }
376