Contents of /trunk/src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


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