FIX:build: Make --disable-nls and --with-included-gettext work.
[navit-package] / navit / gui / gtk / destination.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <fcntl.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <gtk/gtk.h>
25 #include "debug.h"
26 #include "destination.h"
27 #include "navit.h"
28 #include "item.h"
29 #include "coord.h"
30 #include "track.h"
31 #include "country.h"
32 #include "search.h"
33 #include "projection.h"
34 #include "navit_nls.h"
35
36 #define COL_COUNT 8
37
38 static struct search_param {
39         struct navit *nav;
40         struct mapset *ms;
41         struct search_list *sl;
42         struct attr attr;
43         int partial;
44         GtkWidget *entry_country, *entry_postal, *entry_city, *entry_district;
45         GtkWidget *entry_street, *entry_number;
46         GtkWidget *listbox;
47         GtkWidget *treeview;
48         GtkListStore *liststore;
49         GtkTreeModel *liststore2;
50 } search_param;
51
52 static void button_map(GtkWidget *widget, struct search_param *search)
53 {
54         GtkTreePath *path;
55         GtkTreeViewColumn *focus_column;
56         struct pcoord *c=NULL;
57         GtkTreeIter iter;
58
59         gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &focus_column);
60         if(!path)
61                 return;
62         if(!gtk_tree_model_get_iter(search->liststore2, &iter, path))
63                 return;
64         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1);
65         if (c) {
66                 navit_set_center(search->nav, c);
67         }
68 }
69
70 static char *description(struct search_param *search, GtkTreeIter *iter)
71 {
72         char *desc,*car,*postal,*town,*street;
73         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 0, &car, -1);
74         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 1, &postal, -1);
75         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 2, &town, -1);
76         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), iter, 4, &street, -1);
77         if (search->attr.type == attr_town_name)
78                 desc=g_strdup_printf("%s-%s %s", car, postal, town);
79         else
80                 desc=g_strdup_printf("%s-%s %s, %s", car, postal, town, street);
81         return desc;
82 }
83
84 static void button_destination(GtkWidget *widget, struct search_param *search)
85 {
86         struct pcoord *c=NULL;
87         GtkTreeIter iter;
88         char *desc;
89
90         if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (search->liststore2), &iter))
91                 return;
92         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1);
93         if (c) {
94                 desc=description(search, &iter);
95                 navit_set_destination(search->nav, c, desc);
96                 g_free(desc);
97         }
98 }
99
100 static void button_bookmark(GtkWidget *widget, struct search_param *search)
101 {
102         struct pcoord *c=NULL;
103         GtkTreeIter iter;
104         char *desc;
105
106         if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (search->liststore2), &iter))
107                 return;
108         gtk_tree_model_get (GTK_TREE_MODEL (search->liststore2), &iter, COL_COUNT, &c, -1);
109         if (c) {
110                 desc=description(search, &iter);
111                 navit_add_bookmark(search->nav, c, desc);
112                 g_free(desc);
113         }
114 }
115
116
117 char **columns_text[] = {
118         (char *[]){_n("Car"),_n("Iso2"),_n("Iso3"),_n("Country"),NULL},
119         (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),NULL},
120         (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),_n("Street"),NULL},
121         (char *[]){_n("Car"),_n("Postal"),_n("Town"),_n("District"),_n("Street"),_n("Number"),NULL},
122 };
123
124 static void set_columns(struct search_param *param, int mode)
125 {
126         GList *columns_list,*columns;
127         char **column_text=columns_text[mode];
128         int i=0;
129
130         columns_list=gtk_tree_view_get_columns(GTK_TREE_VIEW(param->treeview));
131         columns=columns_list;
132         while (columns) {
133                 gtk_tree_view_remove_column(GTK_TREE_VIEW(param->treeview), columns->data);
134                 columns=g_list_next(columns);
135         }
136         g_list_free(columns_list);
137         while (*column_text) {
138                 printf("column_text=%p\n", column_text);
139                 printf("*column_text=%s\n", *column_text);
140                 GtkCellRenderer *cell=gtk_cell_renderer_text_new();
141                 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (param->treeview),-1, gettext(*column_text), cell, "text", i, NULL);
142                 i++;
143                 column_text++;
144         }
145
146 }
147
148 static void row_activated(GtkWidget *widget, GtkTreePath *p1, GtkTreeViewColumn *c, struct search_param *search)
149 {
150         GtkTreePath *path;
151         GtkTreeViewColumn *focus_column;
152         GtkTreeIter iter;
153         GtkWidget *entry_widget;
154         char *str;
155         int column;
156
157         dbg(0,"enter\n");
158         gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &focus_column);
159         if(!path)
160                 return;
161         if(!gtk_tree_model_get_iter(search->liststore2, &iter, path))
162                 return;
163         switch(search->attr.type) {
164         case attr_country_all:
165                 entry_widget=search->entry_country;
166                 column=3;
167                 break;
168         case attr_town_name:
169                 entry_widget=search->entry_city;
170                 column=2;
171                 break;
172         case attr_street_name:
173                 entry_widget=search->entry_street;
174                 column=4;
175                 break;
176         default:
177                 dbg(0,"Unknown mode\n");
178                 return;
179         }
180         gtk_tree_model_get(search->liststore2, &iter, column, &str, -1);
181         dbg(0,"str=%s\n", str);
182         search->partial=0;
183         gtk_entry_set_text(GTK_ENTRY(entry_widget), str);
184 }
185
186 static void tree_view_button_release(GtkWidget *widget, GdkEventButton *event, struct search_param *search)
187 {
188         GtkTreePath *path;
189         GtkTreeViewColumn *column;
190         gtk_tree_view_get_cursor(GTK_TREE_VIEW(search->treeview), &path, &column);
191         gtk_tree_view_row_activated(GTK_TREE_VIEW(search->treeview), path, column);
192         
193 }
194 static void
195 next_focus(struct search_param *search, GtkWidget *widget)
196 {
197         if (widget == search->entry_country)
198                 gtk_widget_grab_focus(search->entry_city);
199         if (widget == search->entry_city)
200                 gtk_widget_grab_focus(search->entry_street);
201         if (widget == search->entry_street)
202                 gtk_widget_grab_focus(search->entry_number);
203                 
204 }
205
206 static void changed(GtkWidget *widget, struct search_param *search)
207 {
208         struct search_list_result *res;
209         GtkTreeIter iter;
210
211         search->attr.u.str=(char *)gtk_entry_get_text(GTK_ENTRY(widget));
212         printf("changed %s partial %d\n", search->attr.u.str, search->partial);
213         if (widget == search->entry_country) {
214                 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 3, GTK_SORT_ASCENDING);
215                 dbg(0,"country\n");
216                 search->attr.type=attr_country_all;
217                 set_columns(search, 0);
218         }
219         if (widget == search->entry_postal) {
220                 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 1, GTK_SORT_ASCENDING);
221                 dbg(0,"postal\n");
222                 search->attr.type=attr_town_postal;
223                 if (strlen(search->attr.u.str) < 2)
224                         return;
225                 set_columns(search, 1);
226         }
227         if (widget == search->entry_city) {
228                 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 2, GTK_SORT_ASCENDING);
229                 dbg(0,"town\n");
230                 search->attr.type=attr_town_name;
231                 if (strlen(search->attr.u.str) < 3)
232                         return;
233                 set_columns(search, 1);
234         }
235         if (widget == search->entry_street) {
236                 dbg(0,"street\n");
237                 search->attr.type=attr_street_name;
238                 set_columns(search, 2);
239         }
240
241
242         search_list_search(search->sl, &search->attr, search->partial);
243         gtk_list_store_clear(search->liststore);
244         while((res=search_list_get_result(search->sl))) {
245                 gtk_list_store_append(search->liststore,&iter);
246                 gtk_list_store_set(search->liststore,&iter,COL_COUNT,res->c,-1);
247                 if (widget == search->entry_country) {
248                         if (res->country) {
249                                 gtk_list_store_set(search->liststore,&iter,0,res->country->car,-1);
250                                 gtk_list_store_set(search->liststore,&iter,1,res->country->iso3,-1);
251                                 gtk_list_store_set(search->liststore,&iter,2,res->country->iso2,-1);
252                                 gtk_list_store_set(search->liststore,&iter,3,res->country->name,-1);
253                         }
254                 } else {
255                         if (res->country)
256                                 gtk_list_store_set(search->liststore,&iter,0,res->country->car,-1);
257                         else
258                                 gtk_list_store_set(search->liststore,&iter,0,"",-1);
259                         if (res->town) {
260                                 gtk_list_store_set(search->liststore,&iter,1,res->town->postal,-1);
261                                 gtk_list_store_set(search->liststore,&iter,2,res->town->name,-1);
262                                 gtk_list_store_set(search->liststore,&iter,3,res->town->district,-1);
263                         } else {
264                                 gtk_list_store_set(search->liststore,&iter,1,"",-1);
265                                 gtk_list_store_set(search->liststore,&iter,2,"",-1);
266                                 gtk_list_store_set(search->liststore,&iter,3,"",-1);
267                         }
268                         if (res->street)
269                                 gtk_list_store_set(search->liststore,&iter,4,res->street->name,-1);
270                         else
271                                 gtk_list_store_set(search->liststore,&iter,4,"",-1);
272
273                 }
274         }
275         if (! search->partial)
276                 next_focus(search, widget);
277         search->partial=1;
278 }
279
280 /* borrowed from gpe-login */
281
282
283 #define MAX_ARGS 8
284
285 static void
286 parse_xkbd_args (const char *cmd, char **argv)
287 {
288         const char *p = cmd;
289         char buf[strlen (cmd) + 1], *bufp = buf;
290         int nargs = 0;
291         int escape = 0, squote = 0, dquote = 0;
292
293         while (*p)
294         {
295                 if (escape)
296                 {
297                         *bufp++ = *p;
298                          escape = 0;
299                 }
300                 else
301                 {
302                         switch (*p)
303                         {
304                         case '\\':
305                                 escape = 1;
306                                 break;
307                         case '"':
308                                 if (squote)
309                                         *bufp++ = *p;
310                                 else
311                                         dquote = !dquote;
312                                 break;
313                         case '\'':
314                                 if (dquote)
315                                         *bufp++ = *p;
316                                 else
317                                         squote = !squote;
318                                 break;
319                         case ' ':
320                                 if (!squote && !dquote)
321                                 {
322                                         *bufp = 0;
323                                         if (nargs < MAX_ARGS)
324                                         argv[nargs++] = strdup (buf);
325                                         bufp = buf;
326                                         break;
327                                 }
328                         default:
329                                 *bufp++ = *p;
330                                 break;
331                         }
332                 }
333                 p++;
334         }
335
336         if (bufp != buf)
337         {
338                 *bufp = 0;
339                 if (nargs < MAX_ARGS)
340                         argv[nargs++] = strdup (buf);
341         }
342         argv[nargs] = NULL;
343 }
344
345 int kbd_pid;
346
347 static int
348 spawn_xkbd (char *xkbd_path, char *xkbd_str)
349 {
350 #ifdef _WIN32 // AF FIXME for WIN32
351     #ifndef F_SETFD
352         #define F_SETFD 2
353     #endif
354 #else
355         char *xkbd_args[MAX_ARGS + 1];
356         int fd[2];
357         char buf[256];
358         char c;
359         int a = 0;
360         size_t n;
361
362         pipe (fd);
363         kbd_pid = fork ();
364         if (kbd_pid == 0)
365         {
366                 close (fd[0]);
367                 if (dup2 (fd[1], 1) < 0)
368                         perror ("dup2");
369                 close (fd[1]);
370                 if (fcntl (1, F_SETFD, 0))
371                         perror ("fcntl");
372                 xkbd_args[0] = (char *)xkbd_path;
373                 xkbd_args[1] = "-xid";
374                 if (xkbd_str)
375                         parse_xkbd_args (xkbd_str, xkbd_args + 2);
376                 else
377                         xkbd_args[2] = NULL;
378                 execvp (xkbd_path, xkbd_args);
379                 perror (xkbd_path);
380                 _exit (1);
381         }
382         close (fd[1]);
383         do {
384                 n = read (fd[0], &c, 1);
385                 if (n)
386                 {
387                         buf[a++] = c;
388                 }
389         } while (n && (c != 10) && (a < (sizeof (buf) - 1)));
390
391         if (a)
392         {
393                 buf[a] = 0;
394                 return atoi (buf);
395         }
396 #endif
397         return 0;
398 }
399
400 int destination_address(struct navit *nav)
401 {
402
403         GtkWidget *window2, *keyboard, *vbox, *table;
404         GtkWidget *label_country;
405         GtkWidget *label_postal, *label_city, *label_district;
406         GtkWidget *label_street, *label_number;
407         GtkWidget *hseparator1,*hseparator2;
408         GtkWidget *button1,*button2,*button3;
409         int i;
410         struct search_param *search=&search_param;
411         struct attr search_attr, country_name, *country_attr;
412         struct tracking *tracking;
413         struct country_search *cs;
414         struct item *item;
415
416
417         search->nav=nav;
418         search->ms=navit_get_mapset(nav);
419         search->sl=search_list_new(search->ms);
420
421         window2 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
422         gtk_window_set_title(GTK_WINDOW(window2),_("Enter Destination"));
423         gtk_window_set_wmclass (GTK_WINDOW (window2), "navit", "Navit");
424         vbox = gtk_vbox_new(FALSE, 0);
425         table = gtk_table_new(3, 8, FALSE);
426
427         search->entry_country = gtk_entry_new();
428         label_country = gtk_label_new(_("Country"));
429         search->entry_postal = gtk_entry_new();
430         gtk_widget_set_sensitive(GTK_WIDGET(search->entry_postal), FALSE);
431         label_postal = gtk_label_new(_("Zip Code"));
432         search->entry_city = gtk_entry_new();
433         label_city = gtk_label_new(_("City"));
434         search->entry_district = gtk_entry_new();
435         gtk_widget_set_sensitive(GTK_WIDGET(search->entry_district), FALSE);
436         label_district = gtk_label_new(_("District/Township"));
437         hseparator1 = gtk_vseparator_new();
438         search->entry_street = gtk_entry_new();
439         label_street = gtk_label_new(_("Street"));
440         search->entry_number = gtk_entry_new();
441         label_number = gtk_label_new(_("Number"));
442         search->treeview=gtk_tree_view_new();
443         search->listbox = gtk_scrolled_window_new (NULL, NULL);
444         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (search->listbox),
445                         GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
446
447         gtk_tree_view_set_model (GTK_TREE_VIEW (search->treeview), NULL);
448         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(search->listbox),search->treeview);
449         {
450                 GType types[COL_COUNT+1];
451                 for(i=0;i<COL_COUNT;i++)
452                         types[i]=G_TYPE_STRING;
453                 types[i]=G_TYPE_POINTER;
454                 search->liststore=gtk_list_store_newv(COL_COUNT+1,types);
455                 search->liststore2=gtk_tree_model_sort_new_with_model(GTK_TREE_MODEL(search->liststore));
456                 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (search->liststore2), 3, GTK_SORT_ASCENDING);
457                 gtk_tree_view_set_model (GTK_TREE_VIEW (search->treeview), GTK_TREE_MODEL(search->liststore2));
458         }
459
460
461
462
463         hseparator2 = gtk_vseparator_new();
464         button1 = gtk_button_new_with_label(_("Map"));
465         button2 = gtk_button_new_with_label(_("Bookmark"));
466         button3 = gtk_button_new_with_label(_("Destination"));
467
468         gtk_table_attach(GTK_TABLE(table), label_country,  0, 1,  0, 1,  0, GTK_FILL, 0, 0);
469         gtk_table_attach(GTK_TABLE(table), label_postal,   1, 2,  0, 1,  0, GTK_FILL, 0, 0);
470         gtk_table_attach(GTK_TABLE(table), label_city,     2, 3,  0, 1,  0, GTK_FILL, 0, 0);
471
472         gtk_table_attach(GTK_TABLE(table), search->entry_country,  0, 1,  1, 2,  0, GTK_FILL, 0, 0);
473         gtk_table_attach(GTK_TABLE(table), search->entry_postal,   1, 2,  1, 2,  0, GTK_FILL, 0, 0);
474         gtk_table_attach(GTK_TABLE(table), search->entry_city,     2, 3,  1, 2,  0, GTK_FILL, 0, 0);
475
476         gtk_table_attach(GTK_TABLE(table), label_district, 0, 1,  2, 3,  0, GTK_FILL, 0, 0);
477         gtk_table_attach(GTK_TABLE(table), label_street,   1, 2,  2, 3,  0, GTK_FILL, 0, 0);
478         gtk_table_attach(GTK_TABLE(table), label_number,   2, 3,  2, 3,  0, GTK_FILL, 0, 0);
479
480         gtk_table_attach(GTK_TABLE(table), search->entry_district, 0, 1,  3, 4,  0, GTK_FILL, 0, 0);
481         gtk_table_attach(GTK_TABLE(table), search->entry_street,   1, 2,  3, 4,  0, GTK_FILL, 0, 0);
482         gtk_table_attach(GTK_TABLE(table), search->entry_number,   2, 3,  3, 4,  0, GTK_FILL, 0, 0);
483
484         gtk_table_attach(GTK_TABLE(table), search->listbox,        0, 3,  4, 5,  GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
485
486         gtk_table_attach(GTK_TABLE(table), button1, 0, 1, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
487         gtk_table_attach(GTK_TABLE(table), button2, 1, 2, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
488         gtk_table_attach(GTK_TABLE(table), button3, 2, 3, 5, 6, GTK_FILL, GTK_FILL, 0, 0);
489
490         g_signal_connect(G_OBJECT(search->entry_country), "changed", G_CALLBACK(changed), search);
491         g_signal_connect(G_OBJECT(search->entry_postal), "changed", G_CALLBACK(changed), search);
492         g_signal_connect(G_OBJECT(search->entry_city), "changed", G_CALLBACK(changed), search);
493         g_signal_connect(G_OBJECT(search->entry_district), "changed", G_CALLBACK(changed), search);
494         g_signal_connect(G_OBJECT(search->entry_street), "changed", G_CALLBACK(changed), search);
495         g_signal_connect(G_OBJECT(search->entry_number), "changed", G_CALLBACK(changed), search);
496         g_signal_connect(G_OBJECT(button1), "clicked", G_CALLBACK(button_map), search);
497         g_signal_connect(G_OBJECT(button2), "clicked", G_CALLBACK(button_bookmark), search);
498         g_signal_connect(G_OBJECT(button3), "clicked", G_CALLBACK(button_destination), search);
499         g_signal_connect(G_OBJECT(search->treeview), "button-release-event", G_CALLBACK(tree_view_button_release), search);
500         g_signal_connect(G_OBJECT(search->treeview), "row_activated", G_CALLBACK(row_activated), search);
501
502         gtk_widget_grab_focus(search->entry_city);
503
504         gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
505         keyboard=gtk_socket_new();
506         gtk_box_pack_end(GTK_BOX(vbox), keyboard, FALSE, FALSE, 0);
507         gtk_container_add(GTK_CONTAINER(window2), vbox);
508 #if 0
509         g_signal_connect(G_OBJECT(listbox), "select-row", G_CALLBACK(select_row), NULL);
510 #endif
511         gtk_widget_show_all(window2);
512
513 #ifndef _WIN32
514         gtk_socket_steal(GTK_SOCKET(keyboard), spawn_xkbd("xkbd","-geometry 200x100"));
515 #endif
516
517         country_attr=country_default();
518         tracking=navit_get_tracking(nav);
519         if (tracking && tracking_get_current_attr(tracking, attr_country_id, &search_attr))
520                 country_attr=&search_attr;
521         if (country_attr) {
522                 cs=country_search_new(country_attr, 0);
523                 item=country_search_get_item(cs);
524                 if (item && item_attr_get(item, attr_country_name, &country_name))
525                         gtk_entry_set_text(GTK_ENTRY(search->entry_country), country_name.u.str);
526                 country_search_destroy(cs);
527         } else {
528                 dbg(0,"warning: no default country found\n");
529         }
530         search->partial=1;
531         return 0;
532 }