]> err.no Git - mapper/blob - src/search.c
Clear (desktop) progress when download is done.
[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_dialog search_dialog;
58 struct _search_dialog {
59         GtkWidget *dialog;
60         GtkWidget *cmb_type;
61         GtkWidget *cmb_category;
62         GtkWidget *list;
63         GtkWidget *search_entry;
64         GtkWidget *label;
65         GtkListStore *store;
66         gdouble lat;
67         gdouble lon;
68         mapper_search_type stype;
69 };
70
71 static search_dialog sd;
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         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
90         return TRUE;
91 } else if (slen<2 && s->stype!=SEARCH_TYPE_POI) {
92         popup_error(s->dialog, _("Query string too short. Minimum 2 characters."));
93         return TRUE;
94 }
95
96 st=g_strdup(gtk_entry_get_text(GTK_ENTRY(s->search_entry)));
97
98 switch (s->stype) {
99         case SEARCH_TYPE_POI:
100                 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);
101         break;
102         case SEARCH_TYPE_WAY:
103                 sres=osm_way_search(s->lat, s->lon, st, &s->store);
104         break;
105         case SEARCH_TYPE_PLACE:
106                 popup_error(s->dialog, "Not yet implemented");
107                 sres=FALSE;
108         break;
109 }
110
111 if (sres==TRUE) {
112         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
113         g_object_unref(G_OBJECT(s->store));
114 } else {
115         s->store=NULL;
116         gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
117 }
118
119 g_free(st);
120 return TRUE;
121 }
122
123 static gboolean
124 search_get_list_item_latlon(GtkWidget *list, gdouble *lat, gdouble *lon)
125 {
126 GtkTreeIter iter;
127 GtkTreeModel *model;
128
129 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
130         return FALSE;
131
132 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
133 if (!model)
134         return FALSE;
135
136 gtk_tree_model_get(model, &iter, ITEM_LAT, lat, -1);
137 gtk_tree_model_get(model, &iter, ITEM_LON, lon, -1);
138 return TRUE;
139 }
140
141 static guint
142 search_get_list_item_id(GtkWidget *list)
143 {
144 guint id;
145 GtkTreeIter iter;
146 GtkTreeModel *model;
147
148 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(list)), NULL, &iter))
149         return 0;
150
151 model=gtk_tree_view_get_model(GTK_TREE_VIEW(list)); 
152 if (!model)
153         return 0;
154
155 gtk_tree_model_get(model, &iter, ITEM_ID, &id, -1);
156 return id;
157 }
158
159 static void
160 search_set_dialog_mode(search_dialog *s)
161 {
162 s->stype=gtk_combo_box_get_active(GTK_COMBO_BOX(s->cmb_type));
163 switch (s->stype) {
164         case SEARCH_TYPE_POI:
165                 gtk_widget_show(s->cmb_category);
166         break;
167         case SEARCH_TYPE_WAY:
168         case SEARCH_TYPE_PLACE:
169                 gtk_widget_hide(s->cmb_category);
170         break;
171         default:
172                 g_assert_not_reached();
173         break;
174 }
175 }
176
177 static gboolean
178 search_type_changed_cb(GtkWidget *widget, gpointer data)
179 {
180 search_dialog *s=(search_dialog *)data;
181 search_set_dialog_mode(s);
182 if (s->store)
183         gtk_list_store_clear(s->store);
184 s->store=NULL;
185 gtk_tree_view_set_model(GTK_TREE_VIEW(s->list), GTK_TREE_MODEL(s->store));
186 return TRUE;
187 }
188
189 static void
190 search_item_activated_cb(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer data)
191 {
192 search_dialog *s=(search_dialog *)data;
193 gdouble lat, lon;
194 GtkTreeIter iter;
195 GtkTreeModel *model;
196
197 if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)), NULL, &iter))
198         return;
199
200 model=gtk_tree_view_get_model(GTK_TREE_VIEW(tree_view)); 
201 if (!model)
202         return;
203
204 gtk_tree_model_get(model, &iter, ITEM_LAT, &lat, -1);
205 gtk_tree_model_get(model, &iter, ITEM_LON, &lon, -1);
206
207 map_center_latlon(lat, lon);
208 g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
209 #if 0
210 gtk_widget_destroy(s->dialog);
211 #endif
212 }
213
214 gboolean
215 mapper_search_dialog(mapper_search_type stype, gdouble lat, gdouble lon)
216 {
217 GtkWidget *sw, *hbox, *label, *btn_search;
218 GtkTreeViewColumn *column;
219 GtkCellRenderer *renderer;
220 gint res;
221
222 sd.store=NULL;
223 sd.lat=lat;
224 sd.lon=lon;
225 sd.stype=stype;
226
227 sd.dialog = gtk_dialog_new_with_buttons(_("Search"),
228                         GTK_WINDOW(_window),
229                         GTK_DIALOG_MODAL,
230                         _("Goto"), 1,
231                         _("Route to"), 2,
232                         _("Edit"), 3,
233                         GTK_STOCK_CLOSE, GTK_RESPONSE_REJECT, 
234                         NULL);
235
236 gtk_window_set_default_size(GTK_WINDOW(sd.dialog), 500, 300);
237
238 hbox = gtk_hbox_new(FALSE, 4),
239 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), hbox, FALSE, FALSE, 0);
240
241 label=gtk_label_new(_("Search:"));
242 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
243
244 sd.cmb_type=gtk_combo_box_new_text();
245 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "POI");
246 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Street");
247 #if 0
248 gtk_combo_box_append_text(GTK_COMBO_BOX(sd.cmb_type), "Place");
249 #endif
250 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_type, FALSE, FALSE, 0);
251
252 sd.cmb_category = category_combo_new();
253 gtk_box_pack_start(GTK_BOX(hbox), sd.cmb_category, FALSE, FALSE, 0);
254 poi_category_combo_populate(sd.cmb_category, 0, TRUE);
255
256 sd.search_entry=gtk_entry_new();
257 gtk_box_pack_start(GTK_BOX(hbox), sd.search_entry, TRUE, TRUE, 0);
258
259 btn_search=gtk_button_new_with_label(_("Search"));
260 gtk_box_pack_start(GTK_BOX(hbox), btn_search, FALSE, FALSE, 0);
261
262 sw = gtk_scrolled_window_new(NULL, NULL);
263 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN);
264 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
265 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(sd.dialog)->vbox), sw, TRUE, TRUE, 0);
266
267 sd.list=gtk_tree_view_new();
268 gtk_tree_selection_set_mode(gtk_tree_view_get_selection (GTK_TREE_VIEW(sd.list)), GTK_SELECTION_SINGLE);
269 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(sd.list), TRUE);
270 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(sd.list), TRUE);
271
272 renderer = gtk_cell_renderer_text_new();
273 column = gtk_tree_view_column_new_with_attributes(_("Location"), renderer, "text", ITEM_LATLON, NULL);
274 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
275
276 renderer = gtk_cell_renderer_text_new();
277 column = gtk_tree_view_column_new_with_attributes(_("Distance"), renderer, "text", ITEM_DIST, NULL);
278 gtk_tree_view_column_set_sort_column_id (column, ITEM_DIST);
279 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
280
281 renderer = gtk_cell_renderer_text_new();
282 column = gtk_tree_view_column_new_with_attributes(_("Label"), renderer, "text", ITEM_LABEL, NULL);
283 gtk_tree_view_column_set_sort_column_id (column, ITEM_LABEL);
284 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
285
286 renderer = gtk_cell_renderer_text_new();
287 column = gtk_tree_view_column_new_with_attributes(_("Category"), renderer, "text", ITEM_CATLAB, NULL);
288 gtk_tree_view_column_set_sort_column_id (column, ITEM_CATLAB);
289 gtk_tree_view_append_column(GTK_TREE_VIEW(sd.list), column);
290
291 gtk_tree_view_set_search_column (GTK_TREE_VIEW(sd.list), ITEM_LABEL);
292 gtk_container_add(GTK_CONTAINER(sw), sd.list);
293
294 sd.label=gtk_label_new("");
295 gtk_box_pack_start(GTK_BOX(hbox), sd.label, FALSE, FALSE, 0);
296
297 g_signal_connect(G_OBJECT(btn_search), "clicked", G_CALLBACK(search_do_cb), &sd);
298 g_signal_connect(G_OBJECT(sd.cmb_type), "changed", G_CALLBACK(search_type_changed_cb), &sd);
299 g_signal_connect(G_OBJECT(sd.list), "row-activated", G_CALLBACK(search_item_activated_cb), &sd);
300
301 gtk_widget_show_all(sd.dialog);
302 gtk_combo_box_set_active(GTK_COMBO_BOX(sd.cmb_type), sd.stype);
303 search_set_dialog_mode(&sd);
304
305 while ((res=gtk_dialog_run(GTK_DIALOG(sd.dialog)))!=GTK_RESPONSE_REJECT) {
306         gdouble lat, lon;
307
308         switch (res) {
309         case 1:
310                 if (search_get_list_item_latlon(sd.list, &lat, &lon)==FALSE) {
311                         popup_error(sd.dialog, _("Select a location from the list."));
312                 } else {
313                         map_center_latlon(lat, lon);
314                         g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
315                 }
316                 continue;
317         break;
318         case 2:
319                 if (search_get_list_item_latlon(sd.list, &_dest.lat, &_dest.lon)==FALSE) {
320                         popup_error(sd.dialog, _("Select a location from the list."));
321                 } else {
322                         _dest.valid=TRUE;
323                         g_idle_add_full(G_PRIORITY_HIGH_IDLE,(GSourceFunc)map_update_location_from_center, NULL, NULL);
324                 }
325                 continue;
326         break;
327         case 3:
328                 switch (sd.stype) {
329                         case SEARCH_TYPE_POI: {
330                                 poi_info *p=NULL;
331                                 guint id;
332                 
333                                 id=search_get_list_item_id(sd.list);
334                                 if (id>0) {
335                                         p=poi_get_by_id(id);
336                                         if (p) {
337                                                 gtk_widget_destroy(sd.dialog);
338                                                 poi_edit_dialog(ACTION_EDIT_POI, p);
339                                                 return TRUE; /* XXX: for now, this is not nice.. */
340                                         } else {
341                                                 popup_error(sd.dialog, _("Failed to fetch POI for editing."));
342                                         }
343                                 }
344                         }
345                         break;
346                         default:
347                                 popup_error(sd.dialog, _("Only POIs can be modified."));
348                         break;
349                 }
350                 continue;
351         break;
352         default:
353                 break;
354         break;
355         }
356 }
357
358 gtk_widget_destroy(sd.dialog);
359 return TRUE;
360 }
361