Contents of /trunk/src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 74 - (hide annotations)
Mon Aug 24 09:23:36 2009 UTC (14 years, 8 months ago) by harbaum
File MIME type: text/plain
File size: 69024 byte(s)
OSD color matching
1 harbaum 1 /*
2     * This file is part of GPXView.
3     *
4     * GPXView is free software: you can redistribute it and/or modify
5     * it under the terms of the GNU General Public License as published by
6     * the Free Software Foundation, either version 3 of the License, or
7     * (at your option) any later version.
8     *
9     * GPXView 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 GPXView. If not, see <http://www.gnu.org/licenses/>.
16     */
17    
18     #include <stdio.h>
19     #include <string.h>
20     #include <math.h>
21    
22     #include <time.h>
23     #include <sys/time.h>
24    
25     #include "gpxview.h"
26     #include "custom_size_renderer.h"
27     #include "custom_rating_renderer.h"
28     #include "custom_type_renderer.h"
29    
30     #ifdef USE_MAEMO
31     #include <hildon/hildon-banner.h>
32     #endif
33    
34     #include <locale.h>
35    
36     extern char *strcasestr (__const char *__haystack, __const char *__needle);
37    
38     #ifdef USE_BREAD_CRUMB_TRAIL
39     static void crumb_add(appdata_t *appdata, char *name, int level,
40     gpointer user_data);
41    
42     enum {
43     CRUMB_GPXLIST = 0,
44     CRUMB_CACHELIST,
45     CRUMB_SEARCH_GLOBAL,
46     CRUMB_SEARCH_GPX,
47     CRUMB_CACHE,
48     };
49     #endif
50    
51     /* size of first buffer malloc; start small to exercise grow routines */
52     #define FIRSTSIZE 1
53    
54     void errorf(const char *fmt, ...) {
55     va_list args;
56     char *buf = NULL;
57     size_t bufsize;
58     char *newbuf;
59     size_t nextsize = 0;
60     int outsize;
61    
62     bufsize = 0;
63     for (;;) {
64     if (bufsize == 0) {
65     if ((buf = (char *)malloc(FIRSTSIZE)) == NULL)
66     return;
67    
68     bufsize = 1;
69     } else if ((newbuf = (char *)realloc(buf, nextsize)) != NULL) {
70     buf = newbuf;
71     bufsize = nextsize;
72     } else {
73     free(buf);
74     return;
75     }
76    
77     va_start(args, fmt);
78     outsize = vsnprintf(buf, bufsize, fmt, args);
79     va_end(args);
80    
81     if (outsize == -1) {
82     nextsize = bufsize * 2;
83     } else if (outsize == bufsize) {
84     nextsize = bufsize * 2;
85     } else if (outsize > bufsize) {
86     nextsize = outsize + 2; // Linux!
87     } else if (outsize == bufsize - 1) {
88     nextsize = bufsize * 2;
89     } else {
90     /* Output was not truncated */
91     break;
92     }
93     }
94    
95     GtkWidget *dialog = gtk_message_dialog_new(
96     GTK_WINDOW(NULL),
97     GTK_DIALOG_DESTROY_WITH_PARENT,
98     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
99     buf);
100    
101     gtk_window_set_title(GTK_WINDOW(dialog), _("ERROR"));
102    
103     gtk_dialog_run(GTK_DIALOG(dialog));
104     gtk_widget_destroy(dialog);
105    
106     free(buf);
107     }
108    
109     gpx_t *choose_file(appdata_t *appdata, gboolean whole_dir) {
110     GtkWidget *dialog;
111     gpx_t *gpx = NULL;
112    
113     #ifdef USE_MAEMO
114     dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(appdata->window),
115     whole_dir?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
116     GTK_FILE_CHOOSER_ACTION_OPEN);
117    
118     #ifdef HILDON_HELP
119     hildon_help_dialog_help_enable(GTK_DIALOG(dialog),
120     HELP_ID_IMPORT, appdata->osso_context);
121     #endif
122     #else
123 harbaum 11 dialog = gtk_file_chooser_dialog_new (whole_dir?_("Import directory"):
124     _("Import file"),
125 harbaum 1 GTK_WINDOW(appdata->window),
126     whole_dir?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
127     GTK_FILE_CHOOSER_ACTION_OPEN,
128     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
129     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
130     NULL);
131     #endif
132    
133     /* use path if one is present */
134     if(appdata->path)
135     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
136     appdata->path);
137    
138     gtk_widget_show_all (GTK_WIDGET(dialog));
139     if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
140     char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
141    
142     gpx_dialog_t *dialog = gpx_busy_dialog_new(GTK_WIDGET(appdata->window));
143    
144     if(!whole_dir)
145     gpx = gpx_parse(dialog, filename);
146     else {
147     /* cur trailing '/' if present */
148     if(strlastchr(filename) == '/')
149     filename[strlen(filename)] = 0;
150    
151     gpx = gpx_parse_dir(dialog, filename);
152     }
153    
154     gpx_busy_dialog_destroy(dialog);
155    
156     /* save path if gpx was successfully loaded */
157     if(gpx) {
158     char *r = strrchr(filename, '/');
159    
160     /* there is a delimiter, use everything left of it as path */
161     if(r && !whole_dir) {
162     *r = 0;
163     if(appdata->path) free(appdata->path);
164     appdata->path = strdup(filename);
165     /* restore path ... just in case ... */
166     *r = '/';
167     }
168    
169     if(whole_dir)
170     appdata->path = strdup(filename);
171 harbaum 74 } else
172     errorf(_("Load error"));
173 harbaum 1
174     g_free (filename);
175     }
176    
177     gtk_widget_destroy (dialog);
178    
179     return gpx;
180     }
181    
182     /******************** begin of cachelist ********************/
183    
184     enum {
185     CACHELIST_COL_TYPE = 0,
186     CACHELIST_COL_ID,
187     CACHELIST_COL_NAME,
188     CACHELIST_COL_SIZE,
189     CACHELIST_COL_RATING,
190     CACHELIST_COL_BEARING,
191     CACHELIST_COL_DISTANCE,
192     CACHELIST_COL_DATA,
193     CACHELIST_COL_AVAIL,
194     CACHELIST_COL_ARCHIVE,
195     CACHELIST_NUM_COLS
196     } ;
197    
198     void cachelist_view_onRowActivated(GtkTreeView *treeview,
199     GtkTreePath *path,
200     GtkTreeViewColumn *col,
201     gpointer userdata) {
202     appdata_t *appdata = (appdata_t*)userdata;
203     GtkTreeIter iter;
204     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
205    
206 harbaum 45 #ifdef USE_MAEMO
207 harbaum 43 /* check if a cache is already selected and ignore click if yes */
208     /* (was probably a double click) */
209     if(appdata->cur_cache) return;
210 harbaum 45 #endif
211 harbaum 43
212 harbaum 1 if(gtk_tree_model_get_iter(model, &iter, path)) {
213     cache_t *cache;
214     gtk_tree_model_get(model, &iter, CACHELIST_COL_DATA, &cache, -1);
215     #ifndef USE_BREAD_CRUMB_TRAIL
216     cache_dialog(appdata, cache);
217     #else
218     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
219     appdata->cur_view = cache_view(appdata, cache);
220     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
221     gtk_widget_show_all(appdata->vbox);
222    
223     crumb_add(appdata, cache->name, CRUMB_CACHE, cache);
224     #endif
225     }
226     }
227    
228     typedef struct {
229     appdata_t *appdata;
230     GtkTreePath *path;
231     gboolean done;
232     } cachelist_expose_t;
233    
234     static gboolean cachelist_expose(GtkWidget *widget, GdkEventExpose *event,
235     gpointer user_data) {
236     cachelist_expose_t *ce = (cachelist_expose_t*)user_data;
237    
238     if(event->type == GDK_EXPOSE) {
239     if(ce->path && !ce->done) {
240     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(widget),
241     ce->path, NULL, TRUE, 0.5, 0.5);
242     gtk_tree_path_free(ce->path);
243     ce->done = TRUE;
244     }
245     }
246    
247     return FALSE;
248     }
249    
250     static void cachelist_destroy(GtkWidget *widget, gpointer user_data) {
251     cachelist_expose_t *ce = (cachelist_expose_t*)user_data;
252    
253     printf("cachelist timer removed\n");
254     g_assert(ce->appdata->cachelist_handler_id);
255     gtk_timeout_remove(ce->appdata->cachelist_handler_id);
256     ce->appdata->cachelist_handler_id = 0;
257    
258     free(user_data);
259     }
260    
261     #define CACHELIST_UPDATE_TIMEOUT (30000)
262    
263     static GtkWidget *cachelist_create(appdata_t *appdata, gpx_t *gpx,
264     cache_t *sel_cache);
265    
266     void cachelist_redraw(appdata_t *appdata) {
267     #ifndef USE_MAEMO
268     // gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
269     // appdata->cur_view = gpxlist_create_view_and_model(appdata, NULL);
270     // gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
271     // gtk_widget_show_all(appdata->vbox);
272     #else
273    
274 harbaum 11 if(!appdata->cur_view) {
275     printf("cachelist redraw: no active view\n");
276     return;
277     }
278    
279 harbaum 1 g_assert(!appdata->cur_cache);
280     int redraw = 0;
281     if(appdata->search_results)
282     redraw = 1;
283     else {
284     if(appdata->cur_gpx)
285     redraw = 2; // redraw cachelist
286     }
287    
288     if(redraw) {
289 harbaum 11 GtkWidget *container = appdata->vbox;
290    
291     printf("redraw %d\n", redraw);
292    
293     #ifdef USE_STACKABLE_WINDOW
294     HildonWindowStack *stack = hildon_window_stack_get_default();
295     container = hildon_window_stack_peek(stack);
296     #endif
297    
298     gtk_container_remove(GTK_CONTAINER(container), appdata->cur_view);
299 harbaum 1 switch(redraw) {
300     case 1:
301     appdata->cur_view = cachelist_create(appdata,
302     appdata->search_results, NULL);
303     break;
304     case 2:
305     appdata->cur_view = cachelist_create(appdata,
306     appdata->cur_gpx, NULL);
307     break;
308     }
309    
310 harbaum 11 #ifdef USE_STACKABLE_WINDOW
311     if(container != appdata->vbox)
312     gtk_container_add(GTK_CONTAINER(container), appdata->cur_view);
313     else
314     #endif
315     gtk_box_pack_start_defaults(GTK_BOX(container), appdata->cur_view);
316    
317     gtk_widget_show_all(container);
318 harbaum 1 }
319     #endif
320     }
321    
322    
323     static gboolean cachelist_update(gpointer data) {
324    
325     printf("cachelist timer fired!\n");
326    
327     #ifdef USE_MAEMO
328     appdata_t *appdata = (appdata_t*)data;
329    
330 harbaum 11 if(appdata->cur_cache)
331     return TRUE;
332    
333 harbaum 1 if(appdata->cachelist_disable_screensaver)
334     if (osso_display_blanking_pause(appdata->osso_context) != OSSO_OK)
335     fprintf(stderr, "error with display blank\n");
336    
337     if(appdata->cachelist_update)
338     cachelist_redraw(appdata);
339     #endif
340    
341     return TRUE;
342     }
343    
344     static void cachelist_timer_reset(appdata_t *appdata) {
345 harbaum 11 printf("cachelist timer reset\n");
346 harbaum 1 g_assert(appdata->cachelist_handler_id);
347     gtk_timeout_remove(appdata->cachelist_handler_id);
348     appdata->cachelist_handler_id =
349     gtk_timeout_add(CACHELIST_UPDATE_TIMEOUT, cachelist_update, appdata);
350     }
351    
352     static gboolean cachelist_update_reset0(GtkWidget *widget,
353     GdkEventButton *event,
354     gpointer user_data) {
355     cachelist_timer_reset((appdata_t*)user_data);
356     return FALSE;
357     }
358    
359     static void cachelist_update_reset1(GtkAdjustment *adj,
360     gpointer user_data) {
361     cachelist_timer_reset((appdata_t*)user_data);
362     }
363    
364     static GtkWidget *cachelist_create(appdata_t *appdata, gpx_t *gpx,
365     cache_t *sel_cache) {
366     GtkCellRenderer *renderer;
367     GtkWidget *view;
368     GtkListStore *store;
369     GtkTreeIter iter;
370    
371     if(!gpx->notes_loaded) {
372     notes_load_all(appdata, gpx);
373     gpx->notes_loaded = TRUE;
374     }
375    
376     appdata->cur_items = appdata->cachelist_items;
377    
378     /* first sort the caches */
379     pos_t *refpos = get_pos(appdata);
380     gpx_sort(gpx, GPX_SORT_BY_DISTANCE, refpos);
381    
382     view = gtk_tree_view_new();
383    
384     /* --- "Type" column --- */
385     renderer = custom_cell_renderer_type_new();
386     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
387     -1, "Type", renderer, "type", CACHELIST_COL_TYPE, NULL);
388    
389     /* --- "Id" column --- */
390     if(appdata->cachelist_items & CACHELIST_ITEM_ID) {
391     renderer = gtk_cell_renderer_text_new();
392     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
393     -1, "Id", renderer, "text", CACHELIST_COL_ID, NULL);
394     }
395    
396     /* --- "Name" column --- */
397     renderer = gtk_cell_renderer_text_new();
398     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
399    
400     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
401     "Name", renderer, "text", CACHELIST_COL_NAME, NULL);
402     gtk_tree_view_column_set_expand(column, TRUE);
403     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
404    
405     g_object_set(renderer, "foreground", "#ff0000", NULL );
406     gtk_tree_view_column_add_attribute(column, renderer, "strikethrough",
407     CACHELIST_COL_AVAIL);
408     gtk_tree_view_column_add_attribute(column, renderer,
409     "foreground-set", CACHELIST_COL_ARCHIVE);
410    
411     /* --- "Size" column --- */
412     if(appdata->cachelist_items & CACHELIST_ITEM_SIZE) {
413     renderer = custom_cell_renderer_size_new();
414     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
415     -1, "Size", renderer, "size", CACHELIST_COL_SIZE, NULL);
416     }
417    
418     /* --- "Rating" column --- */
419     if(appdata->cachelist_items & CACHELIST_ITEM_RATING) {
420     renderer = custom_cell_renderer_rating_new();
421     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
422     -1, "Rating", renderer, "rating", CACHELIST_COL_RATING, NULL);
423     }
424    
425     /* --- "Bearing" column --- */
426     renderer = gtk_cell_renderer_pixbuf_new();
427     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
428     -1, "Bearing", renderer, "pixbuf", CACHELIST_COL_BEARING, NULL);
429    
430     /* --- "Distance" column --- */
431     renderer = gtk_cell_renderer_text_new();
432     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
433     -1, "Distance", renderer, "text", CACHELIST_COL_DISTANCE, NULL);
434    
435     store = gtk_list_store_new(CACHELIST_NUM_COLS, G_TYPE_INT,
436     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
437     G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING,
438     G_TYPE_POINTER, G_TYPE_BOOLEAN,
439     G_TYPE_BOOLEAN);
440    
441     GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
442    
443     GtkTreeIter sel_iter;
444     gboolean sel_iter_valid = FALSE;
445     GtkTreePath *path = NULL;
446     cache_t *cache = gpx->cache;
447     while(cache) {
448     char str[32];
449     gpx_pos_get_distance_str(str, sizeof(str),
450     *refpos, gpx_cache_pos(cache), appdata->imperial);
451    
452     int dint = (int)(cache->difficulty*2-2);
453     if(dint < 0) dint = 0;
454     if(dint > 8) dint = 8;
455    
456     int tint = (int)(cache->terrain*2-2);
457     if(tint < 0) tint = 0;
458     if(tint > 8) tint = 8;
459    
460     /* cache type includes "solved" flag in lowest bit */
461     int type = (cache->type<<8) +
462     (cache->notes?4:0) +
463     ((cache->notes && cache->notes->override)?1:0) +
464     ((cache->notes && cache->notes->found)?2:0);
465    
466     if((!(type & 2)) || !appdata->cachelist_hide_found) {
467    
468     /* Append a row and fill in some data */
469     gtk_list_store_append (store, &iter);
470    
471     gtk_list_store_set(store, &iter,
472     CACHELIST_COL_TYPE, type,
473     CACHELIST_COL_ID, cache->id,
474     CACHELIST_COL_NAME, cache->name,
475     CACHELIST_COL_SIZE, cache->container,
476     CACHELIST_COL_RATING, 100 * dint + tint,
477     CACHELIST_COL_BEARING,
478     icon_bearing(*refpos, gpx_cache_pos(cache)),
479     CACHELIST_COL_DISTANCE, str,
480     CACHELIST_COL_DATA, cache,
481     CACHELIST_COL_AVAIL, !cache->available ||
482     cache->archived,
483     CACHELIST_COL_ARCHIVE, cache->archived,
484     -1);
485    
486     if(cache == sel_cache) {
487     sel_iter = iter;
488     sel_iter_valid = TRUE;
489     }
490     }
491    
492     cache = cache->next;
493     }
494    
495     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
496     g_object_unref(store);
497    
498     if(sel_iter_valid) {
499     gtk_tree_selection_select_iter(sel, &sel_iter);
500     path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &sel_iter);
501     }
502    
503     /* make list react on clicks */
504     g_signal_connect(view, "row-activated",
505     (GCallback)cachelist_view_onRowActivated, appdata);
506    
507     cachelist_expose_t *ce = malloc(sizeof(cachelist_expose_t));
508     ce->appdata = appdata;
509     ce->path = path;
510     ce->done = FALSE;
511    
512     g_signal_connect(view, "expose-event",
513     (GCallback)cachelist_expose, ce);
514     g_signal_connect(view, "destroy",
515     (GCallback)cachelist_destroy, ce);
516    
517     /* put this inside a scrolled view */
518     #ifndef USE_PANNABLE_AREA
519     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
520     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
521     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
522     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
523     #else
524     GtkWidget *pannable_area = hildon_pannable_area_new();
525    
526     gtk_container_add(GTK_CONTAINER(pannable_area), view);
527     #endif
528    
529     /* add a timer for automatic update */
530     g_assert(!appdata->cachelist_handler_id);
531     appdata->cachelist_handler_id =
532     gtk_timeout_add(CACHELIST_UPDATE_TIMEOUT, cachelist_update, appdata);
533    
534     /* update timer is being reset if the user scrolls or selects */
535     g_signal_connect(view, "button-press-event",
536     (GCallback)cachelist_update_reset0, appdata);
537    
538     #ifndef USE_PANNABLE_AREA
539     g_signal_connect(gtk_scrolled_window_get_vadjustment(
540     GTK_SCROLLED_WINDOW(scrolled_window)),
541     "value-changed",
542     (GCallback)cachelist_update_reset1, appdata);
543    
544     return scrolled_window;
545     #else
546     g_signal_connect(hildon_pannable_area_get_vadjustment(
547     HILDON_PANNABLE_AREA(pannable_area)),
548     "value-changed",
549     (GCallback)cachelist_update_reset1, appdata);
550    
551    
552     return pannable_area;
553     #endif
554     }
555    
556     #ifndef USE_MAEMO
557     void cachelist_dialog(appdata_t *appdata, gpx_t *gpx) {
558     GtkWidget *dialog =
559     gtk_dialog_new_with_buttons(gpx->name, GTK_WINDOW(appdata->window),
560     GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_MODAL |
561     GTK_DIALOG_DESTROY_WITH_PARENT,
562     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
563     NULL);
564    
565     gtk_window_set_default_size(GTK_WINDOW(dialog), DIALOG_WIDTH, DIALOG_HEIGHT);
566    
567     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
568     cachelist_create(appdata, gpx, NULL));
569    
570     gtk_widget_show_all(dialog);
571    
572     gtk_dialog_run(GTK_DIALOG(dialog));
573     gtk_widget_destroy(dialog);
574     }
575     #else
576     #ifdef USE_STACKABLE_WINDOW
577 harbaum 11 static void search_result_free(gpx_t *result);
578    
579     void on_cachelist_destroy(GtkWidget *widget, appdata_t *appdata) {
580     if(appdata->search_results) {
581     search_result_free(appdata->search_results);
582     appdata->search_results = NULL;
583     }
584     appdata->cur_gpx = NULL;
585    
586     /* restore cur_view */
587     appdata->cur_view = g_object_get_data(G_OBJECT(widget), "cur_view");
588     }
589    
590 harbaum 1 void cachelist_dialog(appdata_t *appdata, gpx_t *gpx) {
591     GtkWidget *window = hildon_stackable_window_new();
592    
593 harbaum 11 /* store last "cur_view" in window */
594     g_object_set_data(G_OBJECT(window), "cur_view", appdata->cur_view);
595 harbaum 1
596 harbaum 11 appdata->cur_gpx = gpx;
597 harbaum 34 char *title = g_strdup_printf("%s - GPXView", gpx->name);
598 harbaum 11 gtk_window_set_title(GTK_WINDOW(window), title);
599     g_free(title);
600 harbaum 1
601 harbaum 11 appdata->cur_view = cachelist_create(appdata, gpx, NULL);
602     gtk_container_add(GTK_CONTAINER(window), appdata->cur_view);
603    
604    
605 harbaum 3 hildon_window_set_app_menu(HILDON_WINDOW(window),
606     menu_create(appdata, MENU_CACHELIST));
607    
608 harbaum 11 g_signal_connect(G_OBJECT(window), "destroy",
609     G_CALLBACK(on_cachelist_destroy), appdata);
610    
611 harbaum 1 gtk_widget_show_all(window);
612     }
613     #endif
614     #endif
615    
616     /******************** end of cachelist ********************/
617    
618     /******************** begin of gpxlist ********************/
619    
620     enum {
621     GPXLIST_COL_ICON = 0,
622     GPXLIST_COL_FILENAME,
623     GPXLIST_COL_NAME,
624     GPXLIST_COL_DATE,
625     GPXLIST_COL_CACHES,
626     GPXLIST_COL_OPEN,
627     #ifdef USE_PANNABLE_AREA
628     GPXLIST_COL_DELETE,
629     #endif
630     GPXLIST_COL_DATA,
631     GPXLIST_NUM_COLS
632     } ;
633    
634     static GdkPixbuf *gpx_icon_get(gpx_t *gpx) {
635     if(gpx->filename && g_file_test(gpx->filename, G_FILE_TEST_IS_DIR))
636     return icon_get(ICON_FILE, 1);
637    
638     if(gpx->filename&& !strcasecmp(gpx->filename+strlen(gpx->filename)-4,".zip"))
639     return icon_get(ICON_FILE, 2);
640    
641     return icon_get(ICON_FILE, 0);
642     }
643    
644     static void gpxlist_set(GtkListStore *store, GtkTreeIter *iter, gpx_t *gpx) {
645     char date_str[32], cnum[32];
646    
647     if(gpx->year && gpx->month && gpx->day) {
648     GDate *date = g_date_new_dmy(gpx->day, gpx->month, gpx->year);
649     g_date_strftime(date_str, sizeof(date_str), "%x", date);
650     g_date_free(date);
651     } else
652     strcpy(date_str, "---");
653    
654     char *fname = strrchr(gpx->filename, '/');
655     if(!fname) fname = gpx->filename;
656     else fname++; /* skip '/' */
657    
658     snprintf(cnum, sizeof(cnum), "%d", gpx_total_caches(gpx));
659    
660     /* Append a row and fill in some data */
661     gtk_list_store_set(store, iter,
662     GPXLIST_COL_ICON, gpx_icon_get(gpx),
663     GPXLIST_COL_FILENAME, fname,
664     GPXLIST_COL_NAME, gpx->name,
665     GPXLIST_COL_DATE, gpx->closed?NULL:date_str,
666     GPXLIST_COL_OPEN, !gpx->closed,
667     GPXLIST_COL_CACHES, gpx->closed?NULL:cnum,
668     #ifdef USE_PANNABLE_AREA
669     GPXLIST_COL_DELETE, icon_get(ICON_MISC, 7),
670     #endif
671     GPXLIST_COL_DATA, gpx,
672     -1);
673     }
674    
675     static void gpxlist_remove(appdata_t *appdata,
676     GtkListStore *store, GtkTreeIter *iter,
677     gpx_t *gpx) {
678    
679     printf("removing %s\n", gpx->name);
680    
681     /* de-chain */
682     gpx_t **prev = &appdata->gpx;
683     while(*prev != gpx) prev = &((*prev)->next);
684     *prev = gpx->next;
685    
686     /* remove gconf entry if file was closed */
687     gconf_remove_closed_name(appdata, gpx->filename);
688    
689     /* free gpx itself */
690     gpx_free(gpx);
691    
692     /* and remove from store */
693     gtk_list_store_remove(store, iter);
694     }
695    
696     static void gpxlist_close(appdata_t *appdata,
697     GtkListStore *store, GtkTreeIter *iter,
698     gpx_t *gpx) {
699    
700     printf("closing %s\n", gpx->name);
701    
702     g_assert(!gpx->closed);
703     gpx->closed = TRUE;
704    
705     /* free all associated caches */
706     gpx_free_caches(gpx);
707    
708     /* update entry */
709     gpxlist_set(store, iter, gpx);
710    
711     /* save name in gconf so we know this has been closed */
712     gconf_save_closed_name(appdata, gpx->filename, gpx->name);
713     }
714    
715     static void gpxlist_view_onRowActivated(GtkTreeView *treeview,
716     GtkTreePath *path,
717     GtkTreeViewColumn *col,
718     gpointer userdata) {
719     appdata_t *appdata = (appdata_t*)userdata;
720     GtkTreeIter iter;
721     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
722    
723 harbaum 45 #ifdef USE_MAEMO
724 harbaum 43 /* check if a cache is already selected and ignore click if yes */
725     /* (was probably a double click) */
726     if(appdata->cur_gpx) return;
727 harbaum 45 #endif
728 harbaum 43
729 harbaum 1 if (gtk_tree_model_get_iter(model, &iter, path)) {
730     gpx_t *gpx;
731     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
732    
733     #ifdef USE_PANNABLE_AREA
734     /* get name of column the user clicked on */
735     const char *col_name = NULL;
736     if(col) col_name = gtk_tree_view_column_get_title(col);
737    
738     if(col_name && !strcmp(col_name, "Del")) {
739     printf("clicked delete\n");
740    
741     /* ask user what he wants */
742     GtkWidget *dialog = gtk_message_dialog_new(
743     GTK_WINDOW(appdata->window),
744     GTK_DIALOG_DESTROY_WITH_PARENT,
745     GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL,
746     _("Do you want to close this entry only or do "
747     "you want to remove it completely from the list?"));
748    
749     gtk_dialog_add_buttons(GTK_DIALOG(dialog),
750     _("Remove"), 1,
751     _("Close"), 2,
752     NULL);
753    
754     if(gpx->closed)
755     gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), 2, FALSE);
756    
757     gtk_window_set_title(GTK_WINDOW(dialog), _("Remove entry?"));
758    
759     /* set the active flag again if the user answered "no" */
760     switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
761    
762     case 1:
763     gpxlist_remove(appdata, GTK_LIST_STORE(model), &iter, gpx);
764     break;
765    
766     case 2:
767     gpxlist_close(appdata, GTK_LIST_STORE(model), &iter, gpx);
768     break;
769    
770     default:
771     break;
772     }
773    
774     gtk_widget_destroy(dialog);
775    
776     } else
777     #endif
778     {
779    
780     /* this gpx file may be closed. Since the user definitely wants */
781     /* to use it, we just open it again */
782     if(gpx->closed) {
783     gpx_dialog_t *dialog =
784     gpx_busy_dialog_new(GTK_WIDGET(appdata->window));
785     gpx_t *new = NULL;
786    
787     if(g_file_test(gpx->filename, G_FILE_TEST_IS_DIR))
788     new = gpx_parse_dir(dialog, gpx->filename);
789     else
790     new = gpx_parse(dialog, gpx->filename);
791    
792     if(new) {
793     gpx_t **prev = &(appdata->gpx);
794     while(*prev && *prev != gpx)
795     prev = &(*prev)->next;
796    
797     /* this entry _must_ be in the list */
798     g_assert(*prev);
799    
800     /* replace gpx entry with the new "open" one */
801     (*prev) = new;
802     new->next = gpx->next;
803     gpx->next = NULL;
804    
805     /* free old closed one */
806     gpx_free(gpx);
807    
808     gpx = new;
809    
810     /* finally update the visible list */
811     gpxlist_set(appdata->gpxstore, &iter, gpx);
812    
813     /* and remove gconf entry */
814     gconf_remove_closed_name(appdata, gpx->filename);
815    
816     #ifndef USE_PANNABLE_AREA
817     gtk_widget_set_sensitive(appdata->menu_close, TRUE);
818     #endif
819     } else {
820     printf("unable to reopen file %s\n", gpx->filename);
821     return;
822     }
823    
824     gpx_busy_dialog_destroy(dialog);
825     }
826     #ifndef USE_BREAD_CRUMB_TRAIL
827 harbaum 12 #ifdef USE_STACKABLE_WINDOW
828 harbaum 11 if(!appdata->cur_gpx)
829 harbaum 12 #endif
830 harbaum 11 cachelist_dialog(appdata, gpx);
831 harbaum 12 #ifdef USE_STACKABLE_WINDOW
832 harbaum 11 else
833     printf("selected gpx, but cachelist window already present\n");
834 harbaum 12 #endif
835 harbaum 1 #else
836     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
837     appdata->cur_view = cachelist_create(appdata, gpx, NULL);
838     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
839     gtk_widget_show_all(appdata->vbox);
840    
841     crumb_add(appdata, gpx->name, CRUMB_CACHELIST, gpx);
842     #endif
843     }
844     }
845     }
846    
847     #ifndef USE_PANNABLE_AREA
848     static gboolean
849     view_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
850     GtkTreePath *path, gboolean path_currently_selected,
851     gpointer userdata) {
852     appdata_t *appdata = (appdata_t*)userdata;
853     GtkTreeIter iter;
854    
855     if(gtk_tree_model_get_iter(model, &iter, path)) {
856     gpx_t *gpx;
857     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
858    
859     gtk_widget_set_sensitive(appdata->menu_remove, !path_currently_selected);
860    
861     if(!gpx->closed)
862     gtk_widget_set_sensitive(appdata->menu_close, !path_currently_selected);
863     }
864    
865     return TRUE; /* allow selection state to change */
866     }
867     #endif
868    
869     static GtkWidget *gpxlist_create_view_and_model(appdata_t *appdata,
870     gpx_t *sel_gpx) {
871     gpx_t *gpx = appdata->gpx;
872     GtkCellRenderer *renderer;
873    
874     /* saved displayed items */
875     appdata->cur_items = appdata->gpxlist_items;
876    
877     #ifndef USE_PANNABLE_AREA
878     /* nothing selected yet */
879     gtk_widget_set_sensitive(appdata->menu_remove, FALSE);
880     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
881     #endif
882    
883     appdata->gpxview = gtk_tree_view_new ();
884    
885     GtkTreeSelection *selection =
886     gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
887     #ifndef USE_PANNABLE_AREA
888     gtk_tree_selection_set_select_function(selection, view_selection_func,
889     appdata, NULL);
890     #endif
891    
892     /* --- "Icon" column --- */
893     renderer = gtk_cell_renderer_pixbuf_new();
894     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(appdata->gpxview),
895     -1, "Icon", renderer,
896     "pixbuf", GPXLIST_COL_ICON,
897     // "sensitive", GPXLIST_COL_OPEN,
898     NULL);
899    
900     /* --- "FileName" column --- */
901     if(appdata->gpxlist_items & GPXLIST_ITEM_FILENAME) {
902     renderer = gtk_cell_renderer_text_new();
903     gtk_tree_view_insert_column_with_attributes(
904     GTK_TREE_VIEW(appdata->gpxview),
905     -1, "Filename", renderer,
906     "text", GPXLIST_COL_FILENAME,
907     "sensitive", GPXLIST_COL_OPEN,
908     NULL);
909     }
910    
911     /* --- "Name" column --- */
912     renderer = gtk_cell_renderer_text_new();
913     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
914    
915     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
916     "Name", renderer,
917     "text", GPXLIST_COL_NAME,
918     "sensitive", GPXLIST_COL_OPEN,
919     NULL);
920     gtk_tree_view_column_set_expand(column, TRUE);
921     gtk_tree_view_insert_column(GTK_TREE_VIEW(appdata->gpxview), column, -1);
922    
923     /* --- "Date" column --- */
924     if(appdata->gpxlist_items & GPXLIST_ITEM_DATE) {
925     renderer = gtk_cell_renderer_text_new();
926     g_object_set(renderer, "xalign", 1.0, NULL );
927     gtk_tree_view_insert_column_with_attributes(
928     GTK_TREE_VIEW(appdata->gpxview),
929     -1, "Date", renderer,
930     "text", GPXLIST_COL_DATE,
931     "sensitive", GPXLIST_COL_OPEN,
932     NULL);
933     }
934    
935     /* --- "Number of caches" column --- */
936     if(appdata->gpxlist_items & GPXLIST_ITEM_CNUM) {
937     renderer = gtk_cell_renderer_text_new();
938     g_object_set(renderer, "xalign", 1.0, NULL );
939     gtk_tree_view_insert_column_with_attributes(
940     GTK_TREE_VIEW(appdata->gpxview),
941     -1, "#Caches", renderer,
942     "text", GPXLIST_COL_CACHES,
943     "sensitive", GPXLIST_COL_OPEN,
944     NULL);
945     }
946    
947     #ifdef USE_PANNABLE_AREA
948     /* --- "Delete" column --- */
949     renderer = gtk_cell_renderer_pixbuf_new();
950     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(appdata->gpxview),
951     -1, "Del", renderer,
952     "pixbuf", GPXLIST_COL_DELETE,
953     "sensitive", GPXLIST_COL_OPEN,
954     NULL);
955     #endif
956    
957     /* build and fill the store */
958     appdata->gpxstore = gtk_list_store_new(GPXLIST_NUM_COLS, GDK_TYPE_PIXBUF,
959     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
960     G_TYPE_STRING, G_TYPE_BOOLEAN,
961     #ifdef USE_PANNABLE_AREA
962     GDK_TYPE_PIXBUF,
963     #endif
964     G_TYPE_POINTER);
965    
966     GtkTreePath *path = NULL;
967     GtkTreeIter sel_iter;
968     gboolean sel_iter_valid = FALSE;
969     while(gpx) {
970 harbaum 74 /* don't display entries that failed at load */
971     if(!gpx->failed) {
972     GtkTreeIter iter;
973     gtk_list_store_append(appdata->gpxstore, &iter);
974     gpxlist_set(appdata->gpxstore, &iter, gpx);
975    
976     if(gpx == sel_gpx) {
977     sel_iter = iter;
978     sel_iter_valid = TRUE;
979     }
980 harbaum 1 }
981    
982     gpx = gpx->next;
983     }
984    
985     gtk_tree_view_set_model(GTK_TREE_VIEW(appdata->gpxview),
986     GTK_TREE_MODEL(appdata->gpxstore));
987    
988     g_object_unref(appdata->gpxstore);
989    
990     if(sel_iter_valid) {
991     gtk_tree_selection_select_iter(selection, &sel_iter);
992     path = gtk_tree_model_get_path(GTK_TREE_MODEL(appdata->gpxstore),
993     &sel_iter);
994     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(appdata->gpxview),
995     path, NULL, TRUE, 0.0, 0.0);
996     gtk_tree_path_free(path);
997     }
998    
999     /* make list react on clicks */
1000     g_signal_connect(appdata->gpxview, "row-activated",
1001     (GCallback)gpxlist_view_onRowActivated, appdata);
1002    
1003     /* put this inside a scrolled view */
1004     #ifndef USE_PANNABLE_AREA
1005     GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1006     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1007     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1008     gtk_container_add(GTK_CONTAINER(scrolled_window), appdata->gpxview);
1009    
1010     return scrolled_window;
1011     #else
1012     GtkWidget *pannable_area = hildon_pannable_area_new();
1013     gtk_container_add(GTK_CONTAINER(pannable_area), appdata->gpxview);
1014    
1015     return pannable_area;
1016     #endif
1017     }
1018    
1019     /* add last entry in gpx list to visual representation */
1020     static void gpxlist_add(appdata_t *appdata, gpx_t *new) {
1021     GtkTreeIter iter;
1022    
1023     gtk_list_store_append(appdata->gpxstore, &iter);
1024     gpxlist_set(appdata->gpxstore, &iter, new);
1025    
1026     /* and attach entry to end of list */
1027     gpx_t **gpx = &appdata->gpx;
1028     while(*gpx) gpx = &((*gpx)->next);
1029     *gpx = new;
1030     }
1031    
1032     /******************** end of gpxlist ********************/
1033    
1034     /******************** begin of menu *********************/
1035    
1036 harbaum 49 typedef struct {
1037     appdata_t *appdata;
1038     GtkWidget *dialog;
1039     } about_context_t;
1040    
1041     #ifdef ENABLE_BROWSER_INTERFACE
1042     void on_paypal_button_clicked(GtkButton *button, about_context_t *context) {
1043     gtk_dialog_response(GTK_DIALOG(context->dialog), GTK_RESPONSE_ACCEPT);
1044     browser_url(context->appdata,
1045     "https://www.paypal.com/cgi-bin/webscr"
1046     "?cmd=_s-xclick&hosted_button_id=7400558");
1047     }
1048     #endif
1049    
1050 harbaum 1 static void
1051     cb_menu_about(GtkWidget *window, gpointer data) {
1052 harbaum 49 about_context_t context;
1053 harbaum 1
1054 harbaum 49 context.appdata = (appdata_t *)data;
1055 harbaum 1
1056 harbaum 14 #ifdef ENABLE_LIBLOCATION
1057     char *uses = "uses liblocation";
1058     #elif defined(ENABLE_GPSBT)
1059     char *uses = "uses gpsbt and gpsd";
1060     #else
1061     char *uses = "uses gpsd";
1062     #endif
1063    
1064 harbaum 49 const gchar *authors[] = {
1065     "Till Harbaum <till@harbaum.org>",
1066     "John Stowers <john.stowers@gmail.com>",
1067     NULL };
1068 harbaum 14
1069 harbaum 49 context.dialog = g_object_new(GTK_TYPE_ABOUT_DIALOG,
1070     "name", "GPXView",
1071     "version", VERSION,
1072     "copyright", _("Copyright 2008-2009"),
1073     "authors", authors,
1074     "website", _("http://www.harbaum.org/till/maemo"),
1075     "comments", _(uses),
1076     NULL);
1077 harbaum 14
1078 harbaum 49 #ifdef ENABLE_BROWSER_INTERFACE
1079     /* add a way to donate to the project */
1080     GtkWidget *alignment = gtk_alignment_new(0.5, 0, 0, 0);
1081 harbaum 1
1082 harbaum 49 GtkWidget *hbox = gtk_hbox_new(FALSE, 8);
1083     gtk_box_pack_start(GTK_BOX(hbox),
1084 harbaum 50 gtk_label_new(_("Do you like GPXView?")),
1085 harbaum 49 FALSE, FALSE, 0);
1086 harbaum 1
1087 harbaum 49 GtkWidget *button = gtk_button_new();
1088     gtk_button_set_image(GTK_BUTTON(button),
1089     icon_get_widget(ICON_MISC, 8));
1090     gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1091     g_signal_connect(button, "clicked",
1092     G_CALLBACK(on_paypal_button_clicked), &context);
1093     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1094    
1095     gtk_container_add(GTK_CONTAINER(alignment), hbox);
1096     gtk_box_pack_start_defaults(GTK_BOX((GTK_DIALOG(context.dialog))->vbox),
1097     alignment);
1098    
1099     gtk_widget_show_all(alignment);
1100     #endif
1101    
1102     gtk_dialog_run(GTK_DIALOG(context.dialog));
1103     gtk_widget_destroy(context.dialog);
1104 harbaum 1 }
1105    
1106     #if defined(USE_MAEMO) && defined(HILDON_HELP)
1107     static void
1108     cb_menu_help(GtkWidget *window, gpointer data) {
1109     appdata_t *appdata = (appdata_t*)data;
1110    
1111     hildon_help_show(appdata->osso_context, HELP_ID_INTRO, 0);
1112     }
1113     #endif
1114    
1115     static void
1116     cb_menu_add(GtkWidget *window, gpointer data) {
1117     appdata_t *appdata = (appdata_t *)data;
1118    
1119     gpx_t *new = choose_file(appdata, FALSE);
1120     if(new) gpxlist_add(appdata, new);
1121     }
1122    
1123     static void
1124     cb_menu_adddir(GtkWidget *window, gpointer data) {
1125     appdata_t *appdata = (appdata_t *)data;
1126    
1127     gpx_t *new = choose_file(appdata, TRUE);
1128     if(new) gpxlist_add(appdata, new);
1129     }
1130    
1131     #ifndef USE_PANNABLE_AREA
1132     static void
1133     cb_menu_close(GtkWidget *window, gpointer data) {
1134     appdata_t *appdata = (appdata_t *)data;
1135     GtkTreeSelection *selection;
1136     GtkTreeModel *model;
1137     GtkTreeIter iter;
1138    
1139     printf("selected close\n");
1140    
1141     /* the entry cannot be closed again */
1142     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
1143    
1144     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
1145    
1146     printf("gpxlist close\n");
1147    
1148     if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
1149     gpx_t *gpx = NULL;
1150     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
1151    
1152     if(gpx) gpxlist_close(appdata, GTK_LIST_STORE(model), &iter, gpx);
1153     } else {
1154     g_print ("no row selected.\n");
1155     }
1156     }
1157    
1158     static void
1159     cb_menu_remove(GtkWidget *window, gpointer data) {
1160     appdata_t *appdata = (appdata_t *)data;
1161    
1162     /* disable menu item */
1163     gtk_widget_set_sensitive(appdata->menu_remove, FALSE);
1164     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
1165    
1166     GtkTreeModel *model;
1167     GtkTreeIter iter;
1168     GtkTreeSelection *selection =
1169     gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
1170    
1171     printf("gpxlist remove\n");
1172    
1173     if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
1174     gpx_t *gpx = NULL;
1175     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
1176    
1177     if(gpx) gpxlist_remove(appdata, GTK_LIST_STORE(model), &iter, gpx);
1178     } else {
1179     g_print ("no row selected.\n");
1180     }
1181     }
1182    
1183     #endif // !USE_PANNABLE_AREA
1184    
1185     static void search_result_free(gpx_t *result) {
1186     printf("freeing search results\n");
1187    
1188     /* free found chain */
1189     cache_t *cache = result->cache;
1190     while(cache) {
1191     cache_t *next = cache->next;
1192     free(cache);
1193     cache = next;
1194     }
1195     free(result->name);
1196     free(result);
1197     }
1198    
1199     #define MAX_HITS 50
1200    
1201     static time_t localize_time(time_t in) {
1202     time_t ret;
1203     char *tz;
1204     struct tm *tm = localtime(&in);
1205    
1206     tz = getenv("TZ");
1207     setenv("TZ", "", 1);
1208     tzset();
1209     ret = mktime(tm);
1210     if (tz)
1211     setenv("TZ", tz, 1);
1212     else
1213     unsetenv("TZ");
1214     tzset();
1215     return ret;
1216     }
1217    
1218     static int days_ago(time_t in) {
1219     int day_in = localize_time(in) / (60*60*24);
1220     int day_now = localize_time(time(NULL)) / (60*60*24);
1221    
1222     return day_now - day_in;
1223     }
1224    
1225     gpx_t *search_do(appdata_t *appdata, gpx_t *gpx, char *phrase,
1226     int what, gboolean local) {
1227     /* walk through all caches */
1228    
1229     int hits = 0;
1230     gpx_t *found = malloc(sizeof(gpx_t));
1231     memset(found, 0, sizeof(gpx_t));
1232     cache_t **cacheP = &(found->cache);
1233    
1234     if(what & SEARCH_FINDS) {
1235     time_t loc_now = localize_time(time(NULL));
1236     printf("now: %ld days since 1/1/1970, days hour is %ld\n",
1237     loc_now/(60*60*24), loc_now%(60*60*24)/(60*60));
1238     }
1239    
1240     while(gpx && hits < MAX_HITS) {
1241    
1242     /* we need all notes ... */
1243     if(what & SEARCH_FINDS) {
1244     notes_load_all(appdata, gpx);
1245     gpx->notes_loaded = TRUE;
1246     }
1247    
1248     cache_t *cache = gpx->cache;
1249    
1250     while(cache && hits < MAX_HITS) {
1251     gboolean hit = FALSE;
1252    
1253     if(what & SEARCH_FINDS) {
1254     if(cache->notes && cache->notes->found ) {
1255     int days = days_ago(cache->notes->ftime);
1256    
1257     if(cache->id)
1258     printf("find of %s is %d days ago\n", cache->id, days);
1259    
1260     if(days <= appdata->search_days)
1261     hit = 1;
1262     }
1263     } else if(cache->id && (what & SEARCH_ID) &&
1264     strcasestr(cache->id, phrase))
1265     hit = 1;
1266     else if(cache->name && (what & SEARCH_NAME) &&
1267     strcasestr(cache->name, phrase))
1268     hit = 1;
1269     else if(cache->short_description && (what & SEARCH_DESC) &&
1270     strcasestr(cache->short_description, phrase))
1271     hit = 1;
1272     else if(cache->long_description && (what & SEARCH_DESC) &&
1273     strcasestr(cache->long_description, phrase))
1274     hit = 1;
1275     else if(cache->owner && (what & SEARCH_OWNER) &&
1276     strcasestr(cache->owner, phrase))
1277     hit = 1;
1278    
1279     if(hit) {
1280     /* chain a copy of this cache structure into the found list */
1281     *cacheP = malloc(sizeof(cache_t));
1282     memcpy(*cacheP, cache, sizeof(cache_t));
1283     (*cacheP)->next = NULL;
1284     cacheP = &((*cacheP)->next);
1285     hits++;
1286     }
1287     cache = cache->next;
1288     }
1289    
1290     if(!local) gpx = gpx->next;
1291     else gpx = NULL; /* local search within one gpx only */
1292     }
1293    
1294     found->name = strdup(_("Search results"));
1295    
1296     return found;
1297     }
1298    
1299     typedef struct {
1300     appdata_t *appdata;
1301     GtkWidget *entry, *spinner;
1302     GtkWidget *in_id, *in_name, *in_desc, *in_owner, *in_finds;
1303     } search_context_t;
1304    
1305     static void callback_finds_toggled(GtkWidget *widget, gpointer data ) {
1306     search_context_t *context = (search_context_t*)data;
1307    
1308     gboolean in_finds = gtk_toggle_button_get_active(
1309     GTK_TOGGLE_BUTTON(context->in_finds));
1310    
1311     gtk_widget_set_sensitive(context->entry, !in_finds);
1312     gtk_widget_set_sensitive(context->in_id, !in_finds);
1313     gtk_widget_set_sensitive(context->in_name, !in_finds);
1314     gtk_widget_set_sensitive(context->in_desc, !in_finds);
1315     gtk_widget_set_sensitive(context->in_owner, !in_finds);
1316     gtk_widget_set_sensitive(context->spinner, in_finds);
1317     }
1318    
1319     static void
1320     cb_menu_search(GtkWidget *window, gpointer data) {
1321     appdata_t *appdata = (appdata_t *)data;
1322    
1323     search_context_t context;
1324     memset(&context, 0, sizeof(search_context_t));
1325     context.appdata = appdata;
1326    
1327     GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Enter search phrase"),
1328     GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
1329     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1330     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1331     NULL);
1332    
1333     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1334     gtk_label_new(_("Search in:")));
1335    
1336     GtkWidget *table = gtk_table_new(2, 2, TRUE);
1337     gtk_table_set_col_spacing(GTK_TABLE(table), 0, 8);
1338    
1339     context.in_id = gtk_check_button_new_with_label(_("Waypoint IDs"));
1340     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_id),
1341     appdata->search & SEARCH_ID);
1342     gtk_table_attach_defaults(GTK_TABLE(table), context.in_id, 0, 1, 0, 1);
1343    
1344     context.in_name = gtk_check_button_new_with_label(_("Names"));
1345     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_name),
1346     appdata->search & SEARCH_NAME);
1347     gtk_table_attach_defaults(GTK_TABLE(table), context.in_name, 1, 2, 0, 1);
1348    
1349     context.in_desc = gtk_check_button_new_with_label(_("Descriptions"));
1350     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_desc),
1351     appdata->search & SEARCH_DESC);
1352     gtk_table_attach_defaults(GTK_TABLE(table), context.in_desc, 0, 1, 1, 2);
1353    
1354     context.in_owner = gtk_check_button_new_with_label(_("Owner"));
1355     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_owner),
1356     appdata->search & SEARCH_OWNER);
1357     gtk_table_attach_defaults(GTK_TABLE(table), context.in_owner, 1, 2, 1, 2);
1358    
1359     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
1360    
1361     /* -------------------------------------------------------------- */
1362    
1363     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1364     gtk_label_new(_("Search for:")));
1365     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1366     context.entry = gtk_entry_new());
1367     if(appdata->search_str)
1368     gtk_entry_set_text(GTK_ENTRY(context.entry), appdata->search_str);
1369    
1370     /* -------------------------------------------------------------- */
1371    
1372     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1373     gtk_hseparator_new());
1374    
1375     GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1376    
1377     context.in_finds = gtk_check_button_new_with_label(_("Search finds for"));
1378     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_finds),
1379     appdata->search & SEARCH_FINDS);
1380     gtk_box_pack_start_defaults(GTK_BOX(hbox), context.in_finds);
1381     g_signal_connect(G_OBJECT(context.in_finds), "toggled",
1382     G_CALLBACK(callback_finds_toggled), &context);
1383    
1384     #ifndef USE_MAEMO
1385     GtkObject *adj = gtk_adjustment_new(appdata->search_days, 0, 99, 1, 10, 10);
1386     context.spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
1387     #else
1388     context.spinner = hildon_number_editor_new(0, 99);
1389     hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(context.spinner),
1390     appdata->search_days);
1391     #endif
1392     gtk_box_pack_start_defaults(GTK_BOX(hbox), context.spinner);
1393    
1394     gtk_box_pack_start_defaults(GTK_BOX(hbox), gtk_label_new(_("days")));
1395    
1396     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1397    
1398     /* -------------------------------------------------------------- */
1399    
1400     gtk_widget_show_all(dialog);
1401     callback_finds_toggled(NULL, &context);
1402    
1403     if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
1404     char *p = strdup(gtk_entry_get_text(GTK_ENTRY(context.entry)));
1405    
1406     /* update saved search string */
1407     if(appdata->search_str) free(appdata->search_str);
1408     if(strlen(p) > 0)
1409     appdata->search_str = strdup(p);
1410    
1411     #ifndef USE_MAEMO
1412     appdata->search_days = gtk_spin_button_get_value_as_int(
1413     GTK_SPIN_BUTTON(context.spinner));
1414     #else
1415     appdata->search_days = hildon_number_editor_get_value(
1416     HILDON_NUMBER_EDITOR(context.spinner));
1417     #endif
1418    
1419     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_finds)))
1420     appdata->search |= SEARCH_FINDS;
1421     else
1422     appdata->search &= ~SEARCH_FINDS;
1423    
1424     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_id)))
1425     appdata->search |= SEARCH_ID;
1426     else
1427     appdata->search &= ~SEARCH_ID;
1428    
1429     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_name)))
1430     appdata->search |= SEARCH_NAME;
1431     else
1432     appdata->search &= ~SEARCH_NAME;
1433    
1434     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_desc)))
1435     appdata->search |= SEARCH_DESC;
1436     else
1437     appdata->search &= ~SEARCH_DESC;
1438    
1439     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_owner)))
1440     appdata->search |= SEARCH_OWNER;
1441     else
1442     appdata->search &= ~SEARCH_OWNER;
1443    
1444     gtk_widget_destroy(dialog);
1445    
1446     /* don't search if we are asked to search for nothing */
1447     if(((appdata->search & (SEARCH_ID|SEARCH_NAME|SEARCH_DESC|SEARCH_OWNER)) &&
1448     strlen(p) > 0) || (appdata->search & SEARCH_FINDS)) {
1449    
1450     printf("Search for %s (flags = %x)...\n", p, appdata->search);
1451    
1452     #ifndef USE_BREAD_CRUMB_TRAIL
1453 harbaum 12 gpx_t *found =
1454 harbaum 11 search_do(appdata, appdata->gpx, p, appdata->search, FALSE);
1455 harbaum 1
1456     /* do search result dialog here ... */
1457 harbaum 12 cachelist_dialog(appdata, found);
1458 harbaum 11 #ifndef USE_STACKABLE_WINDOW
1459 harbaum 12 search_result_free(found);
1460     #else
1461     appdata->search_results = found;
1462 harbaum 11 #endif
1463 harbaum 1 #else
1464 harbaum 11 gpx_t *found = NULL;
1465    
1466 harbaum 1 if(appdata->cur_gpx)
1467     found = search_do(appdata, appdata->cur_gpx, p, appdata->search, TRUE);
1468     else
1469     found = search_do(appdata, appdata->gpx, p, appdata->search, FALSE);
1470    
1471     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
1472     appdata->cur_view = cachelist_create(appdata, found, NULL);
1473     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
1474     gtk_widget_show_all(appdata->vbox);
1475     crumb_add(appdata, found->name,
1476     appdata->cur_gpx?CRUMB_SEARCH_GPX:CRUMB_SEARCH_GLOBAL, found);
1477     #endif
1478     } else
1479     printf("No valid search: \"%s\" with flags %x!\n", p, appdata->search);
1480    
1481     free(p);
1482     } else
1483     gtk_widget_destroy(dialog);
1484     }
1485    
1486 harbaum 40 static void on_window_destroy (GtkWidget *widget, gpointer data);
1487 harbaum 1
1488     #ifndef USE_MAEMO
1489     static void
1490     cb_menu_quit(GtkWidget *window, gpointer data) {
1491     on_window_destroy(window, data);
1492     }
1493     #endif
1494    
1495 harbaum 2 #ifndef NO_COPY_N_PASTE
1496 harbaum 1 static void
1497     cb_menu_cut(GtkWidget *widget, gpointer data) {
1498     appdata_t *appdata = (appdata_t*)data;
1499    
1500     if(appdata->active_buffer) {
1501     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1502     gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1503     appdata->clipboard, TRUE);
1504     } else
1505     printf("cut: ERROR, not a text buffer\n");
1506     } else
1507     printf("cut: ERROR, no active buffer\n");
1508     }
1509    
1510     static void
1511     cb_menu_copy(GtkWidget *widget, gpointer data) {
1512     appdata_t *appdata = (appdata_t*)data;
1513    
1514     if(appdata->active_buffer) {
1515     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1516     gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1517     appdata->clipboard);
1518     } else if(GTK_WIDGET_TYPE(appdata->active_buffer) == gtk_html_get_type()) {
1519     printf("copy from html buffer\n");
1520     html_copy_to_clipboard(appdata);
1521     } else
1522     printf("copy: ERROR, not a text nor a html buffer\n");
1523     } else
1524     printf("copy: ERROR, no active buffer\n");
1525     }
1526    
1527     static void
1528     cb_menu_paste(GtkWidget *widget, gpointer data) {
1529     appdata_t *appdata = (appdata_t*)data;
1530    
1531     if(appdata->active_buffer) {
1532     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1533     gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1534     appdata->clipboard, NULL, TRUE);
1535     } else
1536     printf("paste: ERROR, not a text buffer\n");
1537     } else
1538     printf("paste: ERROR, no active buffer\n");
1539     }
1540 harbaum 2 #endif
1541 harbaum 1
1542 harbaum 6 static void
1543     cb_menu_export_log(GtkWidget *widget, gpointer data) {
1544     appdata_t *appdata = (appdata_t*)data;
1545     notes_log_export(appdata);
1546     }
1547 harbaum 5
1548 harbaum 6 #ifdef USE_MAEMO
1549     static void
1550     cb_menu_export_mmpoi(GtkWidget *widget, gpointer data) {
1551     appdata_t *appdata = (appdata_t*)data;
1552     mmpoi_export(appdata);
1553     }
1554     #endif
1555 harbaum 5
1556 harbaum 6 static void
1557     cb_menu_export_garmin(GtkWidget *widget, gpointer data) {
1558     appdata_t *appdata = (appdata_t*)data;
1559     garmin_export(appdata);
1560 harbaum 1 }
1561    
1562 harbaum 32 #ifdef ENABLE_OSM_GPS_MAP
1563 harbaum 6 static void
1564 harbaum 32 cb_menu_map(GtkWidget *window, gpointer data) {
1565     map((appdata_t *)data);
1566     }
1567     #endif
1568    
1569     static void
1570 harbaum 6 cb_menu_geomath(GtkWidget *window, gpointer data) {
1571     geomath_dialog((appdata_t *)data);
1572     }
1573 harbaum 5
1574 harbaum 6 static void
1575     cb_menu_geotext(GtkWidget *window, gpointer data) {
1576     geotext_dialog((appdata_t *)data);
1577 harbaum 1 }
1578    
1579 harbaum 6 static void
1580     cb_menu_precpos(GtkWidget *window, gpointer data) {
1581     precise_position((appdata_t *)data);
1582 harbaum 1 }
1583    
1584 harbaum 6 #ifdef USE_STACKABLE_WINDOW
1585 harbaum 30 typedef struct {
1586     char *label, *desc;
1587     GtkSignalFunc activate_cb;
1588     } menu_entry_t;
1589 harbaum 6
1590 harbaum 30 typedef struct {
1591     const char *title;
1592     const menu_entry_t *menu;
1593     int len;
1594     } submenu_t;
1595 harbaum 3
1596 harbaum 30 #define COLUMNS 1
1597 harbaum 4
1598 harbaum 30 void on_submenu_entry_clicked(GtkButton *button, GtkWidget *menu) {
1599 harbaum 5
1600 harbaum 30 /* force closing of submenu dialog */
1601     gtk_dialog_response(GTK_DIALOG(menu), GTK_RESPONSE_NONE);
1602     gtk_widget_hide(menu);
1603    
1604     /* let gtk clean up */
1605     while(gtk_events_pending())
1606     gtk_main_iteration();
1607 harbaum 11 }
1608    
1609 harbaum 30 static GtkWidget *app_submenu_create(appdata_t *appdata,
1610     const submenu_t *submenu) {
1611 harbaum 5
1612 harbaum 30 /* create a oridinary dialog box */
1613     GtkWidget *dialog = gtk_dialog_new();
1614     gtk_window_set_title(GTK_WINDOW(dialog), _(submenu->title));
1615     gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1616     gtk_window_set_transient_for(GTK_WINDOW(dialog),
1617     GTK_WINDOW(appdata->window));
1618     gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
1619 harbaum 5
1620 harbaum 30 GtkWidget *table = gtk_table_new(submenu->len/COLUMNS, COLUMNS, TRUE);
1621     int x = 0, y = 0;
1622 harbaum 11
1623 harbaum 30 const menu_entry_t *menu_entries = submenu->menu;
1624     while(menu_entries->label) {
1625     GtkWidget *button = NULL;
1626 harbaum 21
1627 harbaum 30 button = hildon_button_new_with_text(
1628 harbaum 6 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
1629     HILDON_BUTTON_ARRANGEMENT_VERTICAL,
1630 harbaum 30 _(menu_entries->label), _(menu_entries->desc));
1631 harbaum 5
1632 harbaum 31 /* try to center both texts */
1633     hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.5, 0.5);
1634     hildon_button_set_value_alignment(HILDON_BUTTON(button), 0.5, 0.5);
1635 harbaum 6
1636 harbaum 31 g_signal_connect(button, "clicked",
1637     G_CALLBACK(on_submenu_entry_clicked), dialog);
1638    
1639     g_signal_connect(button, "clicked",
1640     menu_entries->activate_cb, appdata);
1641    
1642 harbaum 30 gtk_table_attach_defaults(GTK_TABLE(table), button, x, x+1, y, y+1);
1643    
1644     x++;
1645     if(x == COLUMNS) { x = 0; y++; }
1646 harbaum 3
1647 harbaum 30 menu_entries++;
1648     }
1649 harbaum 20
1650 harbaum 30 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
1651    
1652     return dialog;
1653 harbaum 3 }
1654    
1655 harbaum 30 /* popup the dialog shaped submenu */
1656     static void submenu_popup(GtkWidget *menu) {
1657     gtk_widget_show_all(menu);
1658     gtk_dialog_run(GTK_DIALOG(menu));
1659     gtk_widget_hide(menu);
1660     }
1661    
1662     static void submenu_cleanup(GtkWidget *menu) {
1663     gtk_widget_destroy(menu);
1664     }
1665    
1666     static const menu_entry_t submenu_export_entries[] = {
1667     { "Export to Maemo Mapper" , "Save a Maemo Mapper POI file",
1668     G_CALLBACK(cb_menu_export_mmpoi) },
1669     { "Export Field Notes", "Save a Garmin Field Notes file",
1670     G_CALLBACK(cb_menu_export_log) },
1671     { "Export Garmin GPX", "Save modified waypoints in GPX file",
1672     G_CALLBACK(cb_menu_export_garmin) },
1673     { NULL, NULL, NULL }
1674     };
1675    
1676     static const submenu_t submenu_export = {
1677     "Export", submenu_export_entries,
1678     sizeof(submenu_export_entries)/sizeof(menu_entry_t)-1
1679     };
1680    
1681     /* the export submenu */
1682     void on_export_clicked(GtkButton *button, appdata_t *appdata) {
1683     if(!appdata->export_menu)
1684     appdata->export_menu = app_submenu_create(appdata, &submenu_export);
1685    
1686     submenu_popup(appdata->export_menu);
1687     }
1688    
1689     static const menu_entry_t submenu_tools_entries[] = {
1690     { "Geomath", "Geocoordinate calculation",
1691     G_CALLBACK(cb_menu_geomath) },
1692     { "Geotext", "Text analysis",
1693     G_CALLBACK(cb_menu_geotext) },
1694     { "Precise Position", "Calculate a precise GPS position",
1695     G_CALLBACK(cb_menu_precpos) },
1696     { NULL, NULL, NULL }
1697     };
1698    
1699     static const submenu_t submenu_tools = {
1700     "Tools", submenu_tools_entries,
1701     sizeof(submenu_tools_entries)/sizeof(menu_entry_t)-1
1702     };
1703    
1704 harbaum 20 /* the tools submenu */
1705     void on_tools_clicked(GtkButton *button, appdata_t *appdata) {
1706     if(!appdata->tools_menu)
1707 harbaum 30 appdata->tools_menu = app_submenu_create(appdata, &submenu_tools);
1708 harbaum 20
1709 harbaum 30 submenu_popup(appdata->tools_menu);
1710 harbaum 20 }
1711    
1712 harbaum 3 HildonAppMenu *menu_create(appdata_t *appdata, int mode) {
1713     GtkWidget *button;
1714     HildonAppMenu *menu = HILDON_APP_MENU(hildon_app_menu_new());
1715    
1716     /* ------- */
1717 harbaum 7 button = gtk_button_new_with_label(_("About"));
1718     g_signal_connect_after(button, "clicked",
1719     G_CALLBACK(cb_menu_about), appdata);
1720     hildon_app_menu_append(menu, GTK_BUTTON(button));
1721    
1722 harbaum 3 button = gtk_button_new_with_label(_("Settings"));
1723     g_signal_connect_after(button, "clicked", G_CALLBACK(cb_menu_settings),
1724     appdata);
1725     hildon_app_menu_append(menu, GTK_BUTTON(button));
1726    
1727     if(mode == MENU_GPXLIST) {
1728     button = gtk_button_new_with_label(_("Import file"));
1729     g_signal_connect_after(button, "clicked",
1730     G_CALLBACK(cb_menu_add), appdata);
1731     hildon_app_menu_append(menu, GTK_BUTTON(button));
1732    
1733 harbaum 7 button = gtk_button_new_with_label(_("Import directory"));
1734 harbaum 3 g_signal_connect_after(button, "clicked",
1735     G_CALLBACK(cb_menu_adddir), appdata);
1736     hildon_app_menu_append(menu, GTK_BUTTON(button));
1737    
1738 harbaum 4 button = gtk_button_new_with_label(_("Export"));
1739     g_signal_connect_after(button, "clicked",
1740     G_CALLBACK(on_export_clicked), appdata);
1741     hildon_app_menu_append(menu, GTK_BUTTON(button));
1742    
1743     button = gtk_button_new_with_label(_("Search"));
1744     g_signal_connect_after(button, "clicked",
1745     G_CALLBACK(cb_menu_search), appdata);
1746     hildon_app_menu_append(menu, GTK_BUTTON(button));
1747     }
1748    
1749 harbaum 5 button = gtk_button_new_with_label(_("Tools"));
1750     g_signal_connect_after(button, "clicked",
1751     G_CALLBACK(on_tools_clicked), appdata);
1752     hildon_app_menu_append(menu, GTK_BUTTON(button));
1753 harbaum 4
1754 harbaum 44 #ifdef ENABLE_OSM_GPS_MAP
1755     if((mode == MENU_GPXLIST) || (mode == MENU_CACHELIST)) {
1756     button = gtk_button_new_with_label(_("Map"));
1757     g_signal_connect_after(button, "clicked",
1758     G_CALLBACK(cb_menu_map), appdata);
1759     hildon_app_menu_append(menu, GTK_BUTTON(button));
1760     }
1761     #endif
1762    
1763 harbaum 15 #ifdef HILDON_HELP
1764     button = gtk_button_new_with_label(_("Help"));
1765     g_signal_connect_after(button, "clicked",
1766     G_CALLBACK(cb_menu_help), appdata);
1767     hildon_app_menu_append(menu, GTK_BUTTON(button));
1768     #endif
1769 harbaum 3
1770 harbaum 15 gtk_widget_show_all(GTK_WIDGET(menu));
1771    
1772 harbaum 3 return menu;
1773     }
1774     #else
1775 harbaum 5
1776 harbaum 1 void menu_create(appdata_t *appdata) {
1777     GtkWidget *menu, *item;
1778     menu = gtk_menu_new();
1779    
1780 harbaum 3 #ifdef USE_BREAD_CRUMB_TRAIL
1781 harbaum 1 appdata->menu_import =
1782     #endif
1783     item = gtk_menu_item_new_with_label(_("Import"));
1784     gtk_menu_append(GTK_MENU_SHELL(menu), item);
1785     GtkWidget *submenu = gtk_menu_new();
1786     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1787    
1788 harbaum 7 item = gtk_menu_item_new_with_label( _("File") );
1789 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1790     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_add), appdata);
1791    
1792 harbaum 7 item = gtk_menu_item_new_with_label( _("Directory") );
1793 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1794     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_adddir), appdata);
1795    
1796     #ifndef USE_PANNABLE_AREA
1797     gtk_menu_append(GTK_MENU_SHELL(submenu), gtk_separator_menu_item_new());
1798    
1799     appdata->menu_close =
1800     item = gtk_menu_item_new_with_label( _("Close") );
1801     gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1802     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_close), appdata);
1803    
1804     appdata->menu_remove =
1805     item = gtk_menu_item_new_with_label( _("Remove") );
1806     gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1807     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_remove), appdata);
1808     #endif
1809    
1810 harbaum 3 #ifdef USE_BREAD_CRUMB_TRAIL
1811 harbaum 1 appdata->menu_export =
1812     #endif
1813     item = gtk_menu_item_new_with_label(_("Export"));
1814     gtk_menu_append(GTK_MENU_SHELL(menu), item);
1815     submenu = gtk_menu_new();
1816     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1817    
1818     #ifdef USE_MAEMO
1819 harbaum 7 item = gtk_menu_item_new_with_label( _("Maemo Mapper POI") );
1820 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1821     g_signal_connect(item, "activate",
1822     GTK_SIGNAL_FUNC(cb_menu_export_mmpoi), appdata);
1823     #endif
1824    
1825 harbaum 7 item = gtk_menu_item_new_with_label( _("Garmin Field Notes") );
1826 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1827     g_signal_connect(item, "activate",
1828     GTK_SIGNAL_FUNC(cb_menu_export_log), appdata);
1829    
1830 harbaum 7 item = gtk_menu_item_new_with_label( _("Garmin GPX") );
1831 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1832     g_signal_connect(item, "activate",
1833     GTK_SIGNAL_FUNC(cb_menu_export_garmin), appdata);
1834    
1835 harbaum 3 #ifdef USE_BREAD_CRUMB_TRAIL
1836 harbaum 1 appdata->menu_search =
1837     #endif
1838 harbaum 7 item = gtk_menu_item_new_with_label( _("Search") );
1839 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(menu), item);
1840     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_search), appdata);
1841    
1842     gtk_menu_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1843 harbaum 2
1844     #ifndef NO_COPY_N_PASTE
1845 harbaum 1 /* ----------- copy'n paste submenu ----------------- */
1846     appdata->clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
1847     gtk_clipboard_set_can_store(appdata->clipboard, NULL, 0);
1848    
1849     item = gtk_menu_item_new_with_label(_("Edit"));
1850     gtk_menu_append(GTK_MENU_SHELL(menu), item);
1851     submenu = gtk_menu_new();
1852     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1853    
1854     appdata->menu_cut = item = gtk_menu_item_new_with_label( _("Cut") );
1855     gtk_widget_set_sensitive(item, FALSE);
1856     gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1857     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_cut), appdata);
1858     appdata->menu_copy = item = gtk_menu_item_new_with_label( _("Copy") );
1859     gtk_widget_set_sensitive(item, FALSE);
1860     gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1861     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_copy), appdata);
1862     appdata->menu_paste = item = gtk_menu_item_new_with_label( _("Paste") );
1863     gtk_widget_set_sensitive(item, FALSE);
1864     gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1865     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_paste), appdata);
1866 harbaum 2 #endif
1867 harbaum 1
1868 harbaum 3 item = gtk_menu_item_new_with_label( _("Settings") );
1869 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(menu), item);
1870     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_settings),
1871     appdata);
1872    
1873     gtk_menu_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1874    
1875 harbaum 32 #ifdef ENABLE_OSM_GPS_MAP
1876     item = gtk_menu_item_new_with_label( _("Map") );
1877 harbaum 63 gtk_menu_append(GTK_MENU_SHELL(menu), item);
1878 harbaum 32 g_signal_connect(item, "activate",
1879     GTK_SIGNAL_FUNC(cb_menu_map), appdata);
1880     #endif
1881    
1882 harbaum 63 item = gtk_menu_item_new_with_label(_("Tools"));
1883     gtk_menu_append(GTK_MENU_SHELL(menu), item);
1884     submenu = gtk_menu_new();
1885     gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
1886    
1887 harbaum 7 item = gtk_menu_item_new_with_label( _("Geomath") );
1888 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1889     g_signal_connect(item, "activate",
1890     GTK_SIGNAL_FUNC(cb_menu_geomath), appdata);
1891    
1892 harbaum 7 item = gtk_menu_item_new_with_label( _("Geotext") );
1893 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1894     g_signal_connect(item, "activate",
1895     GTK_SIGNAL_FUNC(cb_menu_geotext), appdata);
1896    
1897 harbaum 7 item = gtk_menu_item_new_with_label( _("Precise Position") );
1898 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(submenu), item);
1899     g_signal_connect(item, "activate",
1900     GTK_SIGNAL_FUNC(cb_menu_precpos), appdata);
1901    
1902     gtk_menu_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
1903    
1904     #if defined(USE_MAEMO) && defined(HILDON_HELP)
1905 harbaum 7 item = gtk_menu_item_new_with_label( _("Help") );
1906 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(menu), item);
1907     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_help), appdata);
1908     #endif
1909    
1910 harbaum 7 item = gtk_menu_item_new_with_label( _("About") );
1911 harbaum 1 gtk_menu_append(GTK_MENU_SHELL(menu), item);
1912     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_about), appdata);
1913    
1914     #ifndef USE_MAEMO
1915     item = gtk_menu_item_new_with_label( _("Quit") );
1916     gtk_menu_append(GTK_MENU_SHELL(menu), item);
1917     g_signal_connect(item, "activate", GTK_SIGNAL_FUNC(cb_menu_quit), appdata);
1918     #endif
1919    
1920     #ifdef USE_MAEMO
1921     hildon_window_set_menu(appdata->window, GTK_MENU(menu));
1922     #else
1923     /* attach ordinary gtk menu */
1924     GtkWidget *menu_bar = gtk_menu_bar_new();
1925    
1926     GtkWidget *root_menu = gtk_menu_item_new_with_label (_("Menu"));
1927     gtk_widget_show(root_menu);
1928    
1929     gtk_menu_bar_append(menu_bar, root_menu);
1930     gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
1931    
1932     gtk_widget_show(menu_bar);
1933     gtk_box_pack_start(GTK_BOX(appdata->vbox), menu_bar, 0, 0, 0);
1934     #endif
1935     }
1936 harbaum 3 #endif
1937 harbaum 1
1938     /********************* end of menu **********************/
1939    
1940     void cleanup(appdata_t *appdata) {
1941     gpx_free_all(appdata->gpx);
1942     if(appdata->path) free(appdata->path);
1943     if(appdata->image_path) free(appdata->image_path);
1944     if(appdata->search_str) free(appdata->search_str);
1945    
1946 harbaum 30 #ifdef USE_STACKABLE_WINDOW
1947     if(appdata->export_menu) submenu_cleanup(appdata->export_menu);
1948     if(appdata->tools_menu) submenu_cleanup(appdata->tools_menu);
1949     #endif
1950    
1951 harbaum 1 gnome_vfs_shutdown();
1952     icons_free();
1953     gps_release(appdata);
1954    
1955     #ifdef USE_MAEMO
1956     if(appdata->search_results) {
1957     printf("freeing pending search\n");
1958     search_result_free(appdata->search_results);
1959     }
1960    
1961     if(appdata->osso_context)
1962     osso_deinitialize(appdata->osso_context);
1963    
1964     appdata->program = NULL;
1965     #endif
1966    
1967     /* free chain of locations */
1968     location_t *loc = appdata->location;
1969     while(loc) {
1970     location_t *next = loc->next;
1971     if(loc->name) free(loc->name);
1972     free(loc);
1973     loc = next;
1974     }
1975    
1976     puts("everything is gone");
1977     }
1978    
1979 harbaum 40 static void on_window_destroy (GtkWidget *widget, gpointer data) {
1980 harbaum 1 appdata_t *appdata = (appdata_t*)data;
1981    
1982     gconf_save_state(appdata);
1983     gtk_main_quit();
1984     appdata->window = NULL;
1985     }
1986    
1987     gboolean on_window_key_press(GtkWidget *widget,
1988 harbaum 11 GdkEventKey *event, appdata_t *appdata) {
1989 harbaum 1 int handled = FALSE;
1990    
1991     // printf("key event %d\n", event->keyval);
1992    
1993     switch(event->keyval) {
1994     #ifdef USE_MAEMO
1995    
1996     #ifdef HILDON_HARDKEY_INCREASE
1997     case HILDON_HARDKEY_INCREASE:
1998     html_zoom(appdata, TRUE);
1999     handled = TRUE;
2000     break;
2001     #endif
2002    
2003     #ifdef HILDON_HARDKEY_DECREASE
2004     case HILDON_HARDKEY_DECREASE:
2005     html_zoom(appdata, FALSE);
2006     handled = TRUE;
2007     break;
2008     #endif
2009    
2010     #ifdef HILDON_HARDKEY_FULLSCREEN
2011     case HILDON_HARDKEY_FULLSCREEN:
2012     {
2013     appdata->fullscreen = !appdata->fullscreen;
2014    
2015     if(appdata->fullscreen)
2016     gtk_window_fullscreen(GTK_WINDOW(appdata->window));
2017     else
2018     gtk_window_unfullscreen(GTK_WINDOW(appdata->window));
2019    
2020     handled = TRUE;
2021     }
2022     break;
2023     #endif
2024    
2025     #else
2026     case '+':
2027     printf("zoom+\n");
2028     html_zoom(appdata, TRUE);
2029     handled = TRUE;
2030     break;
2031     case '-':
2032     printf("zoom-\n");
2033     html_zoom(appdata, FALSE);
2034     handled = TRUE;
2035     break;
2036     #endif
2037     }
2038    
2039     return handled;
2040     }
2041    
2042     #ifdef USE_BREAD_CRUMB_TRAIL
2043     typedef struct {
2044     int level;
2045     appdata_t *appdata;
2046     gpointer data;
2047     } crumb_t;
2048    
2049     static void
2050     crumb_back(gpointer data) {
2051     crumb_t *crumb = (crumb_t*)data;
2052     printf("crumb_back called with %d\n", crumb->level);
2053    
2054     /* don't do anything if main window has already been destroyed */
2055     if(!crumb->appdata->window) {
2056     printf("Main window gone ...\n");
2057     return;
2058     }
2059    
2060     /* whatever is being displayed: we don't need it anymore */
2061     gtk_container_remove(GTK_CONTAINER(crumb->appdata->vbox),
2062     crumb->appdata->cur_view);
2063    
2064     /* back from cache to cachelist */
2065     if(crumb->level == CRUMB_CACHE) {
2066     gpx_t *gpx = crumb->appdata->search_results;
2067    
2068     if(!gpx) {
2069     gtk_widget_set_sensitive(crumb->appdata->menu_search, TRUE);
2070     gtk_widget_set_sensitive(crumb->appdata->menu_export, TRUE);
2071     printf("no search data found, return to gpx\n");
2072     gpx = crumb->appdata->cur_gpx;
2073     } else
2074     printf("returning to search result\n");
2075    
2076     g_assert(gpx != NULL);
2077    
2078     crumb->appdata->cur_view = cachelist_create(crumb->appdata, gpx,
2079     crumb->appdata->cur_cache);
2080    
2081     /* returning from cache view: invalidate cache reference */
2082     crumb->appdata->cur_cache = NULL;
2083    
2084     gtk_box_pack_start_defaults(GTK_BOX(crumb->appdata->vbox),
2085     crumb->appdata->cur_view);
2086     }
2087    
2088     if(crumb->level == CRUMB_SEARCH_GPX) {
2089     printf("returning from a local search!\n");
2090    
2091     g_assert((gpx_t*)crumb->data == crumb->appdata->search_results);
2092    
2093     search_result_free((gpx_t*)crumb->data);
2094     crumb->appdata->search_results = NULL;
2095    
2096     gtk_widget_set_sensitive(crumb->appdata->menu_search, TRUE);
2097    
2098     crumb->appdata->cur_view = cachelist_create(crumb->appdata,
2099     crumb->appdata->cur_gpx, NULL);
2100     gtk_box_pack_start_defaults(GTK_BOX(crumb->appdata->vbox),
2101     crumb->appdata->cur_view);
2102     }
2103    
2104     /* back from cachelist to gpxlist */
2105     if((crumb->level == CRUMB_CACHELIST) ||
2106     (crumb->level == CRUMB_SEARCH_GLOBAL)) {
2107    
2108     crumb->appdata->cur_view = gpxlist_create_view_and_model(
2109     crumb->appdata, crumb->appdata->cur_gpx);
2110    
2111     /* returning from cachelist/global search view: */
2112     /* invalidate gpx reference */
2113     crumb->appdata->cur_gpx = NULL;
2114    
2115     gtk_box_pack_start_defaults(GTK_BOX(crumb->appdata->vbox),
2116     crumb->appdata->cur_view);
2117    
2118     if((crumb->level == CRUMB_SEARCH_GLOBAL) ||
2119     (crumb->level == CRUMB_SEARCH_GPX)) {
2120     g_assert((gpx_t*)crumb->data == crumb->appdata->search_results);
2121    
2122     search_result_free((gpx_t*)crumb->data);
2123     crumb->appdata->search_results = NULL;
2124     }
2125    
2126     /* enable gpxlist related menu entries */
2127     gtk_widget_set_sensitive(crumb->appdata->menu_import, TRUE);
2128     gtk_widget_set_sensitive(crumb->appdata->menu_search, TRUE);
2129     gtk_widget_set_sensitive(crumb->appdata->menu_export, TRUE);
2130     }
2131    
2132     gtk_widget_show_all(crumb->appdata->vbox);
2133     g_free(data);
2134     }
2135    
2136     static void crumb_add(appdata_t *appdata, char *name, int level,
2137     gpointer user_data) {
2138     crumb_t *crumb = malloc(sizeof(crumb_t));
2139     crumb->level = level;
2140     crumb->appdata = appdata;
2141     crumb->data = user_data;
2142    
2143     printf("crumb_add with level %d\n", level);
2144    
2145     /* save that we are working on search results */
2146     if((level == CRUMB_SEARCH_GLOBAL) ||
2147     (level == CRUMB_SEARCH_GPX)) {
2148     appdata->search_results = (gpx_t*)user_data;
2149    
2150     /* searches cannot be nested */
2151     gtk_widget_set_sensitive(appdata->menu_search, FALSE);
2152     }
2153    
2154     /* save "path" pointers in appdata */
2155     if(crumb->level == CRUMB_CACHELIST)
2156     appdata->cur_gpx = (gpx_t*)user_data;
2157    
2158     if(crumb->level == CRUMB_CACHE) {
2159     appdata->cur_cache = (cache_t*)user_data;
2160     /* the cache view cannot be searched */
2161     gtk_widget_set_sensitive(appdata->menu_search, FALSE);
2162     gtk_widget_set_sensitive(appdata->menu_export, FALSE);
2163     }
2164    
2165     if(level != CRUMB_GPXLIST) {
2166     /* disable gpxlist related menu entries */
2167     gtk_widget_set_sensitive(appdata->menu_import, FALSE);
2168     #ifndef USE_PANNABLE_AREA
2169     gtk_widget_set_sensitive(appdata->menu_remove, FALSE);
2170     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
2171     #endif
2172     }
2173    
2174     hildon_bread_crumb_trail_push_text(HILDON_BREAD_CRUMB_TRAIL(appdata->bct),
2175     name, crumb, (GDestroyNotify)crumb_back);
2176     }
2177     #endif // USE_BREAD_CRUMB_TRAIL
2178    
2179     void main_after_settings_redraw(appdata_t *appdata, int flags) {
2180 harbaum 11 printf("main after settings redraw\n");
2181    
2182     if(!appdata->cur_view) {
2183     printf("no active view\n");
2184     return;
2185     }
2186    
2187 harbaum 1 #ifndef USE_MAEMO
2188     // in non-maemo setup this can only affect the main screen as
2189     // the menu is blocked while a dialog is open. also the main
2190     // screen is always present
2191     if(appdata->gpxlist_items != appdata->cur_items) {
2192     /* re-do the main screen */
2193     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
2194     appdata->cur_view = gpxlist_create_view_and_model(appdata, NULL);
2195     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
2196     gtk_widget_show_all(appdata->vbox);
2197     }
2198     #else
2199     /* a cache screen cannot be changed from the settings and thus doesn't */
2200     /* need to be redrawn */
2201     if(appdata->cur_cache) {
2202     printf("No redraw in cache view required\n");
2203     return;
2204     }
2205    
2206     int redraw = 0; // nothing to redraw
2207    
2208     if(appdata->search_results) {
2209     if((appdata->cur_items != appdata->cachelist_items) || flags)
2210     redraw = 1;
2211     } else {
2212     if(!appdata->cur_gpx) {
2213     if(appdata->cur_items != appdata->gpxlist_items)
2214     redraw = 2; // redraw gpxlist
2215     } else {
2216     if((appdata->cur_items != appdata->cachelist_items) || flags)
2217     redraw = 3; // redraw cachelist
2218     }
2219     }
2220    
2221     if(redraw) {
2222 harbaum 11 GtkWidget *container = appdata->vbox;
2223    
2224     #ifdef USE_STACKABLE_WINDOW
2225     HildonWindowStack *stack = hildon_window_stack_get_default();
2226     container = hildon_window_stack_peek(stack);
2227     #endif
2228    
2229     gtk_container_remove(GTK_CONTAINER(container), appdata->cur_view);
2230 harbaum 1 switch(redraw) {
2231     case 1:
2232     appdata->cur_view = cachelist_create(appdata,
2233     appdata->search_results, NULL);
2234     break;
2235     case 2:
2236     appdata->cur_view = gpxlist_create_view_and_model(appdata, NULL);
2237     break;
2238     case 3:
2239     appdata->cur_view = cachelist_create(appdata,
2240     appdata->cur_gpx, NULL);
2241     break;
2242     }
2243    
2244 harbaum 11 #ifdef USE_STACKABLE_WINDOW
2245     if(container != appdata->vbox)
2246     gtk_container_add(GTK_CONTAINER(container), appdata->cur_view);
2247     else
2248     #endif
2249     gtk_box_pack_start_defaults(GTK_BOX(container), appdata->cur_view);
2250    
2251     gtk_widget_show_all(container);
2252 harbaum 1 }
2253 harbaum 11 #endif // USE_MAEMO
2254 harbaum 1 }
2255    
2256     int main(int argc, char *argv[]) {
2257     appdata_t appdata;
2258    
2259     /* init appdata */
2260     memset(&appdata, 0, sizeof(appdata));
2261    
2262     printf("Using locale for %s in %s\n", PACKAGE, LOCALEDIR);
2263    
2264     setlocale(LC_ALL, "");
2265     bindtextdomain(PACKAGE, LOCALEDIR);
2266     bind_textdomain_codeset(PACKAGE, "UTF-8");
2267     textdomain(PACKAGE);
2268    
2269     /* prepare thread system */
2270     g_thread_init(NULL);
2271    
2272     gtk_init (&argc, &argv);
2273    
2274     #ifdef USE_MAEMO
2275     printf("Installing osso context for \"org.harbaum." APP "\"\n");
2276     appdata.osso_context = osso_initialize("org.harbaum."APP,
2277     VERSION, TRUE, NULL);
2278     if(appdata.osso_context == NULL) {
2279     fprintf(stderr, "error initiating osso context\n");
2280     }
2281    
2282     dbus_register(&appdata);
2283     #endif
2284    
2285     icons_init();
2286    
2287     if(!gnome_vfs_init()) {
2288     g_error("Gnome VFS init failed\n");
2289     }
2290    
2291     #ifdef USE_MAEMO
2292     /* Create the hildon program and setup the title */
2293     appdata.program = HILDON_PROGRAM(hildon_program_get_instance());
2294     g_set_application_name("GPXView");
2295    
2296     /* Create HildonWindow and set it to HildonProgram */
2297     #ifdef USE_STACKABLE_WINDOW
2298     appdata.window = HILDON_WINDOW(hildon_stackable_window_new());
2299     #else
2300     appdata.window = HILDON_WINDOW(hildon_window_new());
2301     #endif
2302     hildon_program_add_window(appdata.program, appdata.window);
2303     #else
2304     /* Create a Window. */
2305     appdata.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2306     /* Set a decent default size for the window. */
2307     gtk_window_set_default_size(GTK_WINDOW(appdata.window), 500, 300);
2308     #endif
2309    
2310 harbaum 12 #if MAEMO_VERSION_MAJOR == 5
2311 harbaum 1 gtk_window_set_title(GTK_WINDOW(appdata.window), "GPXView");
2312 harbaum 12 #endif
2313    
2314 harbaum 1 g_signal_connect(G_OBJECT(appdata.window), "destroy",
2315     G_CALLBACK(on_window_destroy), &appdata);
2316    
2317     g_signal_connect(G_OBJECT(appdata.window), "key_press_event",
2318     G_CALLBACK(on_window_key_press), &appdata);
2319    
2320     appdata.vbox = gtk_vbox_new(FALSE, 2);
2321     gtk_container_add(GTK_CONTAINER(appdata.window), appdata.vbox);
2322 harbaum 3 #ifndef USE_STACKABLE_WINDOW
2323 harbaum 1 menu_create(&appdata);
2324 harbaum 3 #else
2325     hildon_window_set_app_menu(HILDON_WINDOW(appdata.window),
2326     menu_create(&appdata, MENU_GPXLIST));
2327     #endif
2328 harbaum 1
2329     #ifdef USE_BREAD_CRUMB_TRAIL
2330     appdata.bct = hildon_bread_crumb_trail_new();
2331    
2332     gtk_box_pack_start(GTK_BOX(appdata.vbox), appdata.bct, FALSE,FALSE,0);
2333    
2334     hildon_bread_crumb_trail_clear(HILDON_BREAD_CRUMB_TRAIL(appdata.bct));
2335     crumb_add(&appdata, "GPX", CRUMB_GPXLIST, NULL);
2336     #endif
2337    
2338     /* wait for main gui to appear */
2339     gtk_widget_show_all(GTK_WIDGET(appdata.window));
2340     while(gtk_events_pending())
2341     gtk_main_iteration();
2342    
2343     appdata.gconf_client = gconf_client_get_default();
2344     gconf_load_state(&appdata);
2345     gps_init(&appdata);
2346    
2347     appdata.cur_view = gpxlist_create_view_and_model(&appdata, NULL);
2348     gtk_box_pack_start_defaults(GTK_BOX(appdata.vbox), appdata.cur_view);
2349    
2350     gtk_widget_show_all(GTK_WIDGET(appdata.window));
2351     gtk_main();
2352    
2353     cleanup(&appdata);
2354    
2355     return 0;
2356     }