Contents of /trunk/src/main.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 129 - (hide annotations)
Tue Sep 29 14:30:16 2009 UTC (14 years, 7 months ago) by harbaum
File MIME type: text/plain
File size: 69128 byte(s)
BCT cleanup
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 harbaum 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
39 harbaum 1 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 harbaum 123 #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
99     GTK_MESSAGE_ERROR,
100     #else
101     GTK_MESSAGE_OTHER,
102     #endif
103     GTK_BUTTONS_CLOSE, buf);
104 harbaum 1
105     gtk_window_set_title(GTK_WINDOW(dialog), _("ERROR"));
106    
107     gtk_dialog_run(GTK_DIALOG(dialog));
108     gtk_widget_destroy(dialog);
109    
110     free(buf);
111     }
112    
113     gpx_t *choose_file(appdata_t *appdata, gboolean whole_dir) {
114     GtkWidget *dialog;
115     gpx_t *gpx = NULL;
116    
117     #ifdef USE_MAEMO
118     dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(appdata->window),
119     whole_dir?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
120     GTK_FILE_CHOOSER_ACTION_OPEN);
121    
122     #ifdef HILDON_HELP
123     hildon_help_dialog_help_enable(GTK_DIALOG(dialog),
124     HELP_ID_IMPORT, appdata->osso_context);
125     #endif
126     #else
127 harbaum 11 dialog = gtk_file_chooser_dialog_new (whole_dir?_("Import directory"):
128     _("Import file"),
129 harbaum 1 GTK_WINDOW(appdata->window),
130     whole_dir?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
131     GTK_FILE_CHOOSER_ACTION_OPEN,
132     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
133     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
134     NULL);
135     #endif
136    
137     /* use path if one is present */
138     if(appdata->path)
139     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
140     appdata->path);
141    
142     gtk_widget_show_all (GTK_WIDGET(dialog));
143     if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
144     char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
145 harbaum 107
146     if(filename) {
147     gpx_dialog_t *dialog = gpx_busy_dialog_new(GTK_WIDGET(appdata->window));
148 harbaum 1
149 harbaum 107 if(!whole_dir)
150     gpx = gpx_parse(dialog, filename);
151     else {
152     /* cur trailing '/' if present */
153     if(strlastchr(filename) == '/')
154     filename[strlen(filename)] = 0;
155    
156     gpx = gpx_parse_dir(dialog, filename);
157     }
158    
159     gpx_busy_dialog_destroy(dialog);
160    
161     /* save path if gpx was successfully loaded */
162     if(gpx) {
163     char *r = strrchr(filename, '/');
164    
165     /* there is a delimiter, use everything left of it as path */
166     if(r && !whole_dir) {
167     *r = 0;
168     if(appdata->path) free(appdata->path);
169     appdata->path = strdup(filename);
170     /* restore path ... just in case ... */
171     *r = '/';
172     }
173    
174     if(whole_dir)
175     appdata->path = strdup(filename);
176     } else
177     errorf(_("Load error"));
178 harbaum 1
179 harbaum 107 g_free (filename);
180     } else {
181     #ifndef USE_MAEMO
182     errorf(_("Error accessing the file."));
183     #else
184     errorf(_("Error accessing the file. This may happen if the file "
185     "resides on a remote file system. Please copy the file onto "
186     "the device (e.g. onto the memory card) and try again."));
187     #endif
188 harbaum 1 }
189     }
190    
191     gtk_widget_destroy (dialog);
192    
193     return gpx;
194     }
195    
196     /******************** begin of cachelist ********************/
197    
198     enum {
199     CACHELIST_COL_TYPE = 0,
200     CACHELIST_COL_ID,
201     CACHELIST_COL_NAME,
202     CACHELIST_COL_SIZE,
203     CACHELIST_COL_RATING,
204     CACHELIST_COL_BEARING,
205     CACHELIST_COL_DISTANCE,
206     CACHELIST_COL_DATA,
207     CACHELIST_COL_AVAIL,
208     CACHELIST_COL_ARCHIVE,
209     CACHELIST_NUM_COLS
210     } ;
211    
212     void cachelist_view_onRowActivated(GtkTreeView *treeview,
213     GtkTreePath *path,
214     GtkTreeViewColumn *col,
215     gpointer userdata) {
216     appdata_t *appdata = (appdata_t*)userdata;
217     GtkTreeIter iter;
218     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
219    
220 harbaum 45 #ifdef USE_MAEMO
221 harbaum 43 /* check if a cache is already selected and ignore click if yes */
222     /* (was probably a double click) */
223     if(appdata->cur_cache) return;
224 harbaum 45 #endif
225 harbaum 43
226 harbaum 1 if(gtk_tree_model_get_iter(model, &iter, path)) {
227     cache_t *cache;
228     gtk_tree_model_get(model, &iter, CACHELIST_COL_DATA, &cache, -1);
229 harbaum 128 #if !defined(USE_BREAD_CRUMB_TRAIL) && !defined(BCT)
230 harbaum 1 cache_dialog(appdata, cache);
231     #else
232     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
233     appdata->cur_view = cache_view(appdata, cache);
234     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
235     gtk_widget_show_all(appdata->vbox);
236    
237     crumb_add(appdata, cache->name, CRUMB_CACHE, cache);
238     #endif
239     }
240     }
241    
242     typedef struct {
243     appdata_t *appdata;
244     GtkTreePath *path;
245     gboolean done;
246     } cachelist_expose_t;
247    
248     static gboolean cachelist_expose(GtkWidget *widget, GdkEventExpose *event,
249     gpointer user_data) {
250     cachelist_expose_t *ce = (cachelist_expose_t*)user_data;
251    
252     if(event->type == GDK_EXPOSE) {
253     if(ce->path && !ce->done) {
254     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(widget),
255     ce->path, NULL, TRUE, 0.5, 0.5);
256     gtk_tree_path_free(ce->path);
257     ce->done = TRUE;
258     }
259     }
260    
261     return FALSE;
262     }
263    
264     static void cachelist_destroy(GtkWidget *widget, gpointer user_data) {
265     cachelist_expose_t *ce = (cachelist_expose_t*)user_data;
266    
267     printf("cachelist timer removed\n");
268     g_assert(ce->appdata->cachelist_handler_id);
269     gtk_timeout_remove(ce->appdata->cachelist_handler_id);
270     ce->appdata->cachelist_handler_id = 0;
271    
272     free(user_data);
273     }
274    
275     #define CACHELIST_UPDATE_TIMEOUT (30000)
276    
277     static GtkWidget *cachelist_create(appdata_t *appdata, gpx_t *gpx,
278     cache_t *sel_cache);
279    
280     void cachelist_redraw(appdata_t *appdata) {
281 harbaum 11 if(!appdata->cur_view) {
282     printf("cachelist redraw: no active view\n");
283     return;
284     }
285    
286 harbaum 1 g_assert(!appdata->cur_cache);
287     int redraw = 0;
288     if(appdata->search_results)
289     redraw = 1;
290     else {
291     if(appdata->cur_gpx)
292     redraw = 2; // redraw cachelist
293     }
294    
295     if(redraw) {
296 harbaum 11 GtkWidget *container = appdata->vbox;
297    
298     #ifdef USE_STACKABLE_WINDOW
299     HildonWindowStack *stack = hildon_window_stack_get_default();
300     container = hildon_window_stack_peek(stack);
301     #endif
302    
303     gtk_container_remove(GTK_CONTAINER(container), appdata->cur_view);
304 harbaum 1 switch(redraw) {
305     case 1:
306     appdata->cur_view = cachelist_create(appdata,
307     appdata->search_results, NULL);
308     break;
309     case 2:
310     appdata->cur_view = cachelist_create(appdata,
311     appdata->cur_gpx, NULL);
312     break;
313     }
314    
315 harbaum 11 #ifdef USE_STACKABLE_WINDOW
316     if(container != appdata->vbox)
317     gtk_container_add(GTK_CONTAINER(container), appdata->cur_view);
318     else
319     #endif
320     gtk_box_pack_start_defaults(GTK_BOX(container), appdata->cur_view);
321    
322     gtk_widget_show_all(container);
323 harbaum 1 }
324     }
325    
326    
327     static gboolean cachelist_update(gpointer data) {
328    
329     printf("cachelist timer fired!\n");
330    
331     appdata_t *appdata = (appdata_t*)data;
332    
333 harbaum 11 if(appdata->cur_cache)
334     return TRUE;
335    
336 harbaum 129 #ifdef USE_MAEMO
337 harbaum 1 if(appdata->cachelist_disable_screensaver)
338     if (osso_display_blanking_pause(appdata->osso_context) != OSSO_OK)
339     fprintf(stderr, "error with display blank\n");
340 harbaum 129 #endif
341 harbaum 1
342     if(appdata->cachelist_update)
343     cachelist_redraw(appdata);
344 harbaum 122
345 harbaum 1 return TRUE;
346     }
347    
348     static void cachelist_timer_reset(appdata_t *appdata) {
349 harbaum 11 printf("cachelist timer reset\n");
350 harbaum 1 g_assert(appdata->cachelist_handler_id);
351     gtk_timeout_remove(appdata->cachelist_handler_id);
352     appdata->cachelist_handler_id =
353     gtk_timeout_add(CACHELIST_UPDATE_TIMEOUT, cachelist_update, appdata);
354     }
355    
356     static gboolean cachelist_update_reset0(GtkWidget *widget,
357     GdkEventButton *event,
358     gpointer user_data) {
359     cachelist_timer_reset((appdata_t*)user_data);
360     return FALSE;
361     }
362    
363     static void cachelist_update_reset1(GtkAdjustment *adj,
364     gpointer user_data) {
365     cachelist_timer_reset((appdata_t*)user_data);
366     }
367    
368     static GtkWidget *cachelist_create(appdata_t *appdata, gpx_t *gpx,
369     cache_t *sel_cache) {
370     GtkCellRenderer *renderer;
371     GtkWidget *view;
372     GtkListStore *store;
373     GtkTreeIter iter;
374    
375     if(!gpx->notes_loaded) {
376     notes_load_all(appdata, gpx);
377     gpx->notes_loaded = TRUE;
378     }
379    
380     appdata->cur_items = appdata->cachelist_items;
381    
382     /* first sort the caches */
383     pos_t *refpos = get_pos(appdata);
384     gpx_sort(gpx, GPX_SORT_BY_DISTANCE, refpos);
385    
386     view = gtk_tree_view_new();
387    
388     /* --- "Type" column --- */
389     renderer = custom_cell_renderer_type_new();
390     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
391     -1, "Type", renderer, "type", CACHELIST_COL_TYPE, NULL);
392    
393     /* --- "Id" column --- */
394     if(appdata->cachelist_items & CACHELIST_ITEM_ID) {
395     renderer = gtk_cell_renderer_text_new();
396     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
397     -1, "Id", renderer, "text", CACHELIST_COL_ID, NULL);
398     }
399    
400     /* --- "Name" column --- */
401     renderer = gtk_cell_renderer_text_new();
402     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
403    
404     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
405     "Name", renderer, "text", CACHELIST_COL_NAME, NULL);
406     gtk_tree_view_column_set_expand(column, TRUE);
407     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
408    
409     g_object_set(renderer, "foreground", "#ff0000", NULL );
410     gtk_tree_view_column_add_attribute(column, renderer, "strikethrough",
411     CACHELIST_COL_AVAIL);
412     gtk_tree_view_column_add_attribute(column, renderer,
413     "foreground-set", CACHELIST_COL_ARCHIVE);
414    
415     /* --- "Size" column --- */
416     if(appdata->cachelist_items & CACHELIST_ITEM_SIZE) {
417     renderer = custom_cell_renderer_size_new();
418     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
419     -1, "Size", renderer, "size", CACHELIST_COL_SIZE, NULL);
420     }
421    
422     /* --- "Rating" column --- */
423     if(appdata->cachelist_items & CACHELIST_ITEM_RATING) {
424     renderer = custom_cell_renderer_rating_new();
425     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
426     -1, "Rating", renderer, "rating", CACHELIST_COL_RATING, NULL);
427     }
428    
429     /* --- "Bearing" column --- */
430     renderer = gtk_cell_renderer_pixbuf_new();
431     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
432     -1, "Bearing", renderer, "pixbuf", CACHELIST_COL_BEARING, NULL);
433    
434     /* --- "Distance" column --- */
435     renderer = gtk_cell_renderer_text_new();
436     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
437     -1, "Distance", renderer, "text", CACHELIST_COL_DISTANCE, NULL);
438    
439     store = gtk_list_store_new(CACHELIST_NUM_COLS, G_TYPE_INT,
440     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT,
441     G_TYPE_INT, GDK_TYPE_PIXBUF, G_TYPE_STRING,
442     G_TYPE_POINTER, G_TYPE_BOOLEAN,
443     G_TYPE_BOOLEAN);
444    
445     GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
446    
447     GtkTreeIter sel_iter;
448     gboolean sel_iter_valid = FALSE;
449     GtkTreePath *path = NULL;
450     cache_t *cache = gpx->cache;
451     while(cache) {
452     char str[32];
453     gpx_pos_get_distance_str(str, sizeof(str),
454     *refpos, gpx_cache_pos(cache), appdata->imperial);
455    
456     int dint = (int)(cache->difficulty*2-2);
457     if(dint < 0) dint = 0;
458     if(dint > 8) dint = 8;
459    
460     int tint = (int)(cache->terrain*2-2);
461     if(tint < 0) tint = 0;
462     if(tint > 8) tint = 8;
463    
464     /* cache type includes "solved" flag in lowest bit */
465     int type = (cache->type<<8) +
466     (cache->notes?4:0) +
467     ((cache->notes && cache->notes->override)?1:0) +
468     ((cache->notes && cache->notes->found)?2:0);
469    
470     if((!(type & 2)) || !appdata->cachelist_hide_found) {
471    
472     /* Append a row and fill in some data */
473     gtk_list_store_append (store, &iter);
474    
475     gtk_list_store_set(store, &iter,
476     CACHELIST_COL_TYPE, type,
477     CACHELIST_COL_ID, cache->id,
478     CACHELIST_COL_NAME, cache->name,
479     CACHELIST_COL_SIZE, cache->container,
480     CACHELIST_COL_RATING, 100 * dint + tint,
481     CACHELIST_COL_BEARING,
482     icon_bearing(*refpos, gpx_cache_pos(cache)),
483     CACHELIST_COL_DISTANCE, str,
484     CACHELIST_COL_DATA, cache,
485     CACHELIST_COL_AVAIL, !cache->available ||
486     cache->archived,
487     CACHELIST_COL_ARCHIVE, cache->archived,
488     -1);
489    
490     if(cache == sel_cache) {
491     sel_iter = iter;
492     sel_iter_valid = TRUE;
493     }
494     }
495    
496     cache = cache->next;
497     }
498    
499     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
500     g_object_unref(store);
501    
502     if(sel_iter_valid) {
503     gtk_tree_selection_select_iter(sel, &sel_iter);
504     path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &sel_iter);
505     }
506    
507     /* make list react on clicks */
508     g_signal_connect(view, "row-activated",
509     (GCallback)cachelist_view_onRowActivated, appdata);
510    
511     cachelist_expose_t *ce = malloc(sizeof(cachelist_expose_t));
512     ce->appdata = appdata;
513     ce->path = path;
514     ce->done = FALSE;
515    
516     g_signal_connect(view, "expose-event",
517     (GCallback)cachelist_expose, ce);
518     g_signal_connect(view, "destroy",
519     (GCallback)cachelist_destroy, ce);
520    
521     /* put this inside a scrolled view */
522     #ifndef USE_PANNABLE_AREA
523     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
524     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
525     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
526     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
527     #else
528     GtkWidget *pannable_area = hildon_pannable_area_new();
529    
530     gtk_container_add(GTK_CONTAINER(pannable_area), view);
531     #endif
532    
533     /* add a timer for automatic update */
534     g_assert(!appdata->cachelist_handler_id);
535     appdata->cachelist_handler_id =
536     gtk_timeout_add(CACHELIST_UPDATE_TIMEOUT, cachelist_update, appdata);
537    
538 harbaum 129 #ifdef ENABLE_OSM_GPS_MAP
539     map_update(appdata);
540     #endif
541    
542 harbaum 1 /* update timer is being reset if the user scrolls or selects */
543     g_signal_connect(view, "button-press-event",
544     (GCallback)cachelist_update_reset0, appdata);
545    
546     #ifndef USE_PANNABLE_AREA
547     g_signal_connect(gtk_scrolled_window_get_vadjustment(
548     GTK_SCROLLED_WINDOW(scrolled_window)),
549     "value-changed",
550     (GCallback)cachelist_update_reset1, appdata);
551    
552     return scrolled_window;
553     #else
554     g_signal_connect(hildon_pannable_area_get_vadjustment(
555     HILDON_PANNABLE_AREA(pannable_area)),
556     "value-changed",
557     (GCallback)cachelist_update_reset1, appdata);
558    
559    
560     return pannable_area;
561     #endif
562     }
563    
564     #ifndef USE_MAEMO
565     void cachelist_dialog(appdata_t *appdata, gpx_t *gpx) {
566     GtkWidget *dialog =
567     gtk_dialog_new_with_buttons(gpx->name, GTK_WINDOW(appdata->window),
568     GTK_DIALOG_NO_SEPARATOR | GTK_DIALOG_MODAL |
569     GTK_DIALOG_DESTROY_WITH_PARENT,
570     GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
571     NULL);
572    
573     gtk_window_set_default_size(GTK_WINDOW(dialog), DIALOG_WIDTH, DIALOG_HEIGHT);
574    
575     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox),
576     cachelist_create(appdata, gpx, NULL));
577    
578     gtk_widget_show_all(dialog);
579    
580     gtk_dialog_run(GTK_DIALOG(dialog));
581     gtk_widget_destroy(dialog);
582     }
583     #else
584     #ifdef USE_STACKABLE_WINDOW
585 harbaum 11 static void search_result_free(gpx_t *result);
586    
587     void on_cachelist_destroy(GtkWidget *widget, appdata_t *appdata) {
588     if(appdata->search_results) {
589     search_result_free(appdata->search_results);
590     appdata->search_results = NULL;
591     }
592     appdata->cur_gpx = NULL;
593    
594     /* restore cur_view */
595     appdata->cur_view = g_object_get_data(G_OBJECT(widget), "cur_view");
596     }
597    
598 harbaum 1 void cachelist_dialog(appdata_t *appdata, gpx_t *gpx) {
599     GtkWidget *window = hildon_stackable_window_new();
600    
601 harbaum 11 /* store last "cur_view" in window */
602     g_object_set_data(G_OBJECT(window), "cur_view", appdata->cur_view);
603 harbaum 1
604 harbaum 11 appdata->cur_gpx = gpx;
605 harbaum 34 char *title = g_strdup_printf("%s - GPXView", gpx->name);
606 harbaum 11 gtk_window_set_title(GTK_WINDOW(window), title);
607     g_free(title);
608 harbaum 1
609 harbaum 11 appdata->cur_view = cachelist_create(appdata, gpx, NULL);
610     gtk_container_add(GTK_CONTAINER(window), appdata->cur_view);
611    
612    
613 harbaum 3 hildon_window_set_app_menu(HILDON_WINDOW(window),
614     menu_create(appdata, MENU_CACHELIST));
615    
616 harbaum 11 g_signal_connect(G_OBJECT(window), "destroy",
617     G_CALLBACK(on_cachelist_destroy), appdata);
618    
619 harbaum 1 gtk_widget_show_all(window);
620     }
621     #endif
622     #endif
623    
624     /******************** end of cachelist ********************/
625    
626     /******************** begin of gpxlist ********************/
627    
628     enum {
629     GPXLIST_COL_ICON = 0,
630     GPXLIST_COL_FILENAME,
631     GPXLIST_COL_NAME,
632     GPXLIST_COL_DATE,
633     GPXLIST_COL_CACHES,
634     GPXLIST_COL_OPEN,
635     #ifdef USE_PANNABLE_AREA
636     GPXLIST_COL_DELETE,
637     #endif
638     GPXLIST_COL_DATA,
639     GPXLIST_NUM_COLS
640     } ;
641    
642     static GdkPixbuf *gpx_icon_get(gpx_t *gpx) {
643     if(gpx->filename && g_file_test(gpx->filename, G_FILE_TEST_IS_DIR))
644     return icon_get(ICON_FILE, 1);
645    
646     if(gpx->filename&& !strcasecmp(gpx->filename+strlen(gpx->filename)-4,".zip"))
647     return icon_get(ICON_FILE, 2);
648    
649     return icon_get(ICON_FILE, 0);
650     }
651    
652     static void gpxlist_set(GtkListStore *store, GtkTreeIter *iter, gpx_t *gpx) {
653     char date_str[32], cnum[32];
654    
655     if(gpx->year && gpx->month && gpx->day) {
656     GDate *date = g_date_new_dmy(gpx->day, gpx->month, gpx->year);
657     g_date_strftime(date_str, sizeof(date_str), "%x", date);
658     g_date_free(date);
659     } else
660     strcpy(date_str, "---");
661    
662     char *fname = strrchr(gpx->filename, '/');
663     if(!fname) fname = gpx->filename;
664     else fname++; /* skip '/' */
665    
666     snprintf(cnum, sizeof(cnum), "%d", gpx_total_caches(gpx));
667    
668     /* Append a row and fill in some data */
669     gtk_list_store_set(store, iter,
670     GPXLIST_COL_ICON, gpx_icon_get(gpx),
671     GPXLIST_COL_FILENAME, fname,
672     GPXLIST_COL_NAME, gpx->name,
673     GPXLIST_COL_DATE, gpx->closed?NULL:date_str,
674     GPXLIST_COL_OPEN, !gpx->closed,
675     GPXLIST_COL_CACHES, gpx->closed?NULL:cnum,
676     #ifdef USE_PANNABLE_AREA
677     GPXLIST_COL_DELETE, icon_get(ICON_MISC, 7),
678     #endif
679     GPXLIST_COL_DATA, gpx,
680     -1);
681     }
682    
683     static void gpxlist_remove(appdata_t *appdata,
684     GtkListStore *store, GtkTreeIter *iter,
685     gpx_t *gpx) {
686    
687     printf("removing %s\n", gpx->name);
688    
689     /* de-chain */
690     gpx_t **prev = &appdata->gpx;
691     while(*prev != gpx) prev = &((*prev)->next);
692     *prev = gpx->next;
693    
694     /* remove gconf entry if file was closed */
695     gconf_remove_closed_name(appdata, gpx->filename);
696    
697     /* free gpx itself */
698     gpx_free(gpx);
699    
700     /* and remove from store */
701     gtk_list_store_remove(store, iter);
702     }
703    
704     static void gpxlist_close(appdata_t *appdata,
705     GtkListStore *store, GtkTreeIter *iter,
706     gpx_t *gpx) {
707    
708     printf("closing %s\n", gpx->name);
709    
710     g_assert(!gpx->closed);
711     gpx->closed = TRUE;
712    
713     /* free all associated caches */
714     gpx_free_caches(gpx);
715    
716     /* update entry */
717     gpxlist_set(store, iter, gpx);
718    
719     /* save name in gconf so we know this has been closed */
720     gconf_save_closed_name(appdata, gpx->filename, gpx->name);
721     }
722    
723     static void gpxlist_view_onRowActivated(GtkTreeView *treeview,
724     GtkTreePath *path,
725     GtkTreeViewColumn *col,
726     gpointer userdata) {
727     appdata_t *appdata = (appdata_t*)userdata;
728     GtkTreeIter iter;
729     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
730    
731 harbaum 45 #ifdef USE_MAEMO
732 harbaum 43 /* check if a cache is already selected and ignore click if yes */
733     /* (was probably a double click) */
734     if(appdata->cur_gpx) return;
735 harbaum 45 #endif
736 harbaum 43
737 harbaum 1 if (gtk_tree_model_get_iter(model, &iter, path)) {
738     gpx_t *gpx;
739     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
740    
741     #ifdef USE_PANNABLE_AREA
742     /* get name of column the user clicked on */
743     const char *col_name = NULL;
744     if(col) col_name = gtk_tree_view_column_get_title(col);
745    
746     if(col_name && !strcmp(col_name, "Del")) {
747     printf("clicked delete\n");
748    
749     /* ask user what he wants */
750     GtkWidget *dialog = gtk_message_dialog_new(
751     GTK_WINDOW(appdata->window),
752     GTK_DIALOG_DESTROY_WITH_PARENT,
753     GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL,
754     _("Do you want to close this entry only or do "
755     "you want to remove it completely from the list?"));
756    
757     gtk_dialog_add_buttons(GTK_DIALOG(dialog),
758     _("Remove"), 1,
759     _("Close"), 2,
760     NULL);
761    
762     if(gpx->closed)
763     gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), 2, FALSE);
764    
765     gtk_window_set_title(GTK_WINDOW(dialog), _("Remove entry?"));
766    
767     /* set the active flag again if the user answered "no" */
768     switch(gtk_dialog_run(GTK_DIALOG(dialog))) {
769    
770     case 1:
771     gpxlist_remove(appdata, GTK_LIST_STORE(model), &iter, gpx);
772     break;
773    
774     case 2:
775     gpxlist_close(appdata, GTK_LIST_STORE(model), &iter, gpx);
776     break;
777    
778     default:
779     break;
780     }
781    
782     gtk_widget_destroy(dialog);
783    
784     } else
785     #endif
786     {
787    
788     /* this gpx file may be closed. Since the user definitely wants */
789     /* to use it, we just open it again */
790     if(gpx->closed) {
791     gpx_dialog_t *dialog =
792     gpx_busy_dialog_new(GTK_WIDGET(appdata->window));
793     gpx_t *new = NULL;
794    
795     if(g_file_test(gpx->filename, G_FILE_TEST_IS_DIR))
796     new = gpx_parse_dir(dialog, gpx->filename);
797     else
798     new = gpx_parse(dialog, gpx->filename);
799    
800     if(new) {
801     gpx_t **prev = &(appdata->gpx);
802     while(*prev && *prev != gpx)
803     prev = &(*prev)->next;
804    
805     /* this entry _must_ be in the list */
806     g_assert(*prev);
807    
808     /* replace gpx entry with the new "open" one */
809     (*prev) = new;
810     new->next = gpx->next;
811     gpx->next = NULL;
812    
813     /* free old closed one */
814     gpx_free(gpx);
815    
816     gpx = new;
817    
818     /* finally update the visible list */
819     gpxlist_set(appdata->gpxstore, &iter, gpx);
820    
821     /* and remove gconf entry */
822     gconf_remove_closed_name(appdata, gpx->filename);
823    
824     #ifndef USE_PANNABLE_AREA
825     gtk_widget_set_sensitive(appdata->menu_close, TRUE);
826     #endif
827     } else {
828     printf("unable to reopen file %s\n", gpx->filename);
829     return;
830     }
831    
832     gpx_busy_dialog_destroy(dialog);
833     }
834 harbaum 128 #if !defined(USE_BREAD_CRUMB_TRAIL) && !defined(BCT)
835 harbaum 12 #ifdef USE_STACKABLE_WINDOW
836 harbaum 11 if(!appdata->cur_gpx)
837 harbaum 12 #endif
838 harbaum 11 cachelist_dialog(appdata, gpx);
839 harbaum 12 #ifdef USE_STACKABLE_WINDOW
840 harbaum 11 else
841     printf("selected gpx, but cachelist window already present\n");
842 harbaum 12 #endif
843 harbaum 1 #else
844     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
845     appdata->cur_view = cachelist_create(appdata, gpx, NULL);
846     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
847     gtk_widget_show_all(appdata->vbox);
848    
849     crumb_add(appdata, gpx->name, CRUMB_CACHELIST, gpx);
850     #endif
851     }
852     }
853     }
854    
855     #ifndef USE_PANNABLE_AREA
856     static gboolean
857     view_selection_func(GtkTreeSelection *selection, GtkTreeModel *model,
858     GtkTreePath *path, gboolean path_currently_selected,
859     gpointer userdata) {
860     appdata_t *appdata = (appdata_t*)userdata;
861     GtkTreeIter iter;
862    
863     if(gtk_tree_model_get_iter(model, &iter, path)) {
864     gpx_t *gpx;
865     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
866    
867     gtk_widget_set_sensitive(appdata->menu_remove, !path_currently_selected);
868    
869     if(!gpx->closed)
870     gtk_widget_set_sensitive(appdata->menu_close, !path_currently_selected);
871     }
872    
873     return TRUE; /* allow selection state to change */
874     }
875     #endif
876    
877     static GtkWidget *gpxlist_create_view_and_model(appdata_t *appdata,
878     gpx_t *sel_gpx) {
879     gpx_t *gpx = appdata->gpx;
880     GtkCellRenderer *renderer;
881    
882     /* saved displayed items */
883     appdata->cur_items = appdata->gpxlist_items;
884    
885     #ifndef USE_PANNABLE_AREA
886     /* nothing selected yet */
887     gtk_widget_set_sensitive(appdata->menu_remove, FALSE);
888     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
889     #endif
890    
891     appdata->gpxview = gtk_tree_view_new ();
892    
893     GtkTreeSelection *selection =
894     gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
895     #ifndef USE_PANNABLE_AREA
896     gtk_tree_selection_set_select_function(selection, view_selection_func,
897     appdata, NULL);
898     #endif
899    
900     /* --- "Icon" column --- */
901     renderer = gtk_cell_renderer_pixbuf_new();
902     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(appdata->gpxview),
903     -1, "Icon", renderer,
904     "pixbuf", GPXLIST_COL_ICON,
905     // "sensitive", GPXLIST_COL_OPEN,
906     NULL);
907    
908     /* --- "FileName" column --- */
909     if(appdata->gpxlist_items & GPXLIST_ITEM_FILENAME) {
910     renderer = gtk_cell_renderer_text_new();
911     gtk_tree_view_insert_column_with_attributes(
912     GTK_TREE_VIEW(appdata->gpxview),
913     -1, "Filename", renderer,
914     "text", GPXLIST_COL_FILENAME,
915     "sensitive", GPXLIST_COL_OPEN,
916     NULL);
917     }
918    
919     /* --- "Name" column --- */
920     renderer = gtk_cell_renderer_text_new();
921     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
922    
923     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
924     "Name", renderer,
925     "text", GPXLIST_COL_NAME,
926     "sensitive", GPXLIST_COL_OPEN,
927     NULL);
928     gtk_tree_view_column_set_expand(column, TRUE);
929     gtk_tree_view_insert_column(GTK_TREE_VIEW(appdata->gpxview), column, -1);
930    
931     /* --- "Date" column --- */
932     if(appdata->gpxlist_items & GPXLIST_ITEM_DATE) {
933     renderer = gtk_cell_renderer_text_new();
934     g_object_set(renderer, "xalign", 1.0, NULL );
935     gtk_tree_view_insert_column_with_attributes(
936     GTK_TREE_VIEW(appdata->gpxview),
937     -1, "Date", renderer,
938     "text", GPXLIST_COL_DATE,
939     "sensitive", GPXLIST_COL_OPEN,
940     NULL);
941     }
942    
943     /* --- "Number of caches" column --- */
944     if(appdata->gpxlist_items & GPXLIST_ITEM_CNUM) {
945     renderer = gtk_cell_renderer_text_new();
946     g_object_set(renderer, "xalign", 1.0, NULL );
947     gtk_tree_view_insert_column_with_attributes(
948     GTK_TREE_VIEW(appdata->gpxview),
949     -1, "#Caches", renderer,
950     "text", GPXLIST_COL_CACHES,
951     "sensitive", GPXLIST_COL_OPEN,
952     NULL);
953     }
954    
955     #ifdef USE_PANNABLE_AREA
956     /* --- "Delete" column --- */
957     renderer = gtk_cell_renderer_pixbuf_new();
958     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(appdata->gpxview),
959     -1, "Del", renderer,
960     "pixbuf", GPXLIST_COL_DELETE,
961     "sensitive", GPXLIST_COL_OPEN,
962     NULL);
963     #endif
964    
965     /* build and fill the store */
966     appdata->gpxstore = gtk_list_store_new(GPXLIST_NUM_COLS, GDK_TYPE_PIXBUF,
967     G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
968     G_TYPE_STRING, G_TYPE_BOOLEAN,
969     #ifdef USE_PANNABLE_AREA
970     GDK_TYPE_PIXBUF,
971     #endif
972     G_TYPE_POINTER);
973    
974     GtkTreePath *path = NULL;
975     GtkTreeIter sel_iter;
976     gboolean sel_iter_valid = FALSE;
977     while(gpx) {
978 harbaum 113 GtkTreeIter iter;
979     gtk_list_store_append(appdata->gpxstore, &iter);
980     gpxlist_set(appdata->gpxstore, &iter, gpx);
981    
982     if(gpx == sel_gpx) {
983     sel_iter = iter;
984     sel_iter_valid = TRUE;
985 harbaum 1 }
986    
987     gpx = gpx->next;
988     }
989    
990     gtk_tree_view_set_model(GTK_TREE_VIEW(appdata->gpxview),
991     GTK_TREE_MODEL(appdata->gpxstore));
992    
993     g_object_unref(appdata->gpxstore);
994    
995     if(sel_iter_valid) {
996     gtk_tree_selection_select_iter(selection, &sel_iter);
997     path = gtk_tree_model_get_path(GTK_TREE_MODEL(appdata->gpxstore),
998     &sel_iter);
999     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(appdata->gpxview),
1000     path, NULL, TRUE, 0.0, 0.0);
1001     gtk_tree_path_free(path);
1002     }
1003    
1004     /* make list react on clicks */
1005     g_signal_connect(appdata->gpxview, "row-activated",
1006     (GCallback)gpxlist_view_onRowActivated, appdata);
1007    
1008     /* put this inside a scrolled view */
1009     #ifndef USE_PANNABLE_AREA
1010     GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1011     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1012     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1013     gtk_container_add(GTK_CONTAINER(scrolled_window), appdata->gpxview);
1014    
1015     return scrolled_window;
1016     #else
1017     GtkWidget *pannable_area = hildon_pannable_area_new();
1018     gtk_container_add(GTK_CONTAINER(pannable_area), appdata->gpxview);
1019    
1020     return pannable_area;
1021     #endif
1022     }
1023    
1024     /* add last entry in gpx list to visual representation */
1025     static void gpxlist_add(appdata_t *appdata, gpx_t *new) {
1026     GtkTreeIter iter;
1027    
1028     gtk_list_store_append(appdata->gpxstore, &iter);
1029     gpxlist_set(appdata->gpxstore, &iter, new);
1030    
1031     /* and attach entry to end of list */
1032     gpx_t **gpx = &appdata->gpx;
1033     while(*gpx) gpx = &((*gpx)->next);
1034     *gpx = new;
1035     }
1036    
1037     /******************** end of gpxlist ********************/
1038    
1039     /******************** begin of menu *********************/
1040    
1041 harbaum 49 typedef struct {
1042     appdata_t *appdata;
1043     GtkWidget *dialog;
1044     } about_context_t;
1045    
1046     #ifdef ENABLE_BROWSER_INTERFACE
1047     void on_paypal_button_clicked(GtkButton *button, about_context_t *context) {
1048     gtk_dialog_response(GTK_DIALOG(context->dialog), GTK_RESPONSE_ACCEPT);
1049     browser_url(context->appdata,
1050     "https://www.paypal.com/cgi-bin/webscr"
1051     "?cmd=_s-xclick&hosted_button_id=7400558");
1052     }
1053     #endif
1054    
1055 harbaum 1 static void
1056     cb_menu_about(GtkWidget *window, gpointer data) {
1057 harbaum 49 about_context_t context;
1058 harbaum 1
1059 harbaum 49 context.appdata = (appdata_t *)data;
1060 harbaum 1
1061 harbaum 14 #ifdef ENABLE_LIBLOCATION
1062     char *uses = "uses liblocation";
1063     #elif defined(ENABLE_GPSBT)
1064     char *uses = "uses gpsbt and gpsd";
1065     #else
1066     char *uses = "uses gpsd";
1067     #endif
1068    
1069 harbaum 49 const gchar *authors[] = {
1070     "Till Harbaum <till@harbaum.org>",
1071     "John Stowers <john.stowers@gmail.com>",
1072     NULL };
1073 harbaum 14
1074 harbaum 49 context.dialog = g_object_new(GTK_TYPE_ABOUT_DIALOG,
1075     "name", "GPXView",
1076     "version", VERSION,
1077     "copyright", _("Copyright 2008-2009"),
1078     "authors", authors,
1079     "website", _("http://www.harbaum.org/till/maemo"),
1080     "comments", _(uses),
1081     NULL);
1082 harbaum 14
1083 harbaum 49 #ifdef ENABLE_BROWSER_INTERFACE
1084     /* add a way to donate to the project */
1085     GtkWidget *alignment = gtk_alignment_new(0.5, 0, 0, 0);
1086 harbaum 1
1087 harbaum 49 GtkWidget *hbox = gtk_hbox_new(FALSE, 8);
1088     gtk_box_pack_start(GTK_BOX(hbox),
1089 harbaum 50 gtk_label_new(_("Do you like GPXView?")),
1090 harbaum 49 FALSE, FALSE, 0);
1091 harbaum 1
1092 harbaum 49 GtkWidget *button = gtk_button_new();
1093     gtk_button_set_image(GTK_BUTTON(button),
1094     icon_get_widget(ICON_MISC, 8));
1095     gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE);
1096     g_signal_connect(button, "clicked",
1097     G_CALLBACK(on_paypal_button_clicked), &context);
1098     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0);
1099    
1100     gtk_container_add(GTK_CONTAINER(alignment), hbox);
1101     gtk_box_pack_start_defaults(GTK_BOX((GTK_DIALOG(context.dialog))->vbox),
1102     alignment);
1103    
1104     gtk_widget_show_all(alignment);
1105     #endif
1106    
1107     gtk_dialog_run(GTK_DIALOG(context.dialog));
1108     gtk_widget_destroy(context.dialog);
1109 harbaum 1 }
1110    
1111     #if defined(USE_MAEMO) && defined(HILDON_HELP)
1112     static void
1113     cb_menu_help(GtkWidget *window, gpointer data) {
1114     appdata_t *appdata = (appdata_t*)data;
1115    
1116     hildon_help_show(appdata->osso_context, HELP_ID_INTRO, 0);
1117     }
1118     #endif
1119    
1120     static void
1121     cb_menu_add(GtkWidget *window, gpointer data) {
1122     appdata_t *appdata = (appdata_t *)data;
1123    
1124     gpx_t *new = choose_file(appdata, FALSE);
1125     if(new) gpxlist_add(appdata, new);
1126     }
1127    
1128     static void
1129     cb_menu_adddir(GtkWidget *window, gpointer data) {
1130     appdata_t *appdata = (appdata_t *)data;
1131    
1132     gpx_t *new = choose_file(appdata, TRUE);
1133     if(new) gpxlist_add(appdata, new);
1134     }
1135    
1136     #ifndef USE_PANNABLE_AREA
1137     static void
1138     cb_menu_close(GtkWidget *window, gpointer data) {
1139     appdata_t *appdata = (appdata_t *)data;
1140     GtkTreeSelection *selection;
1141     GtkTreeModel *model;
1142     GtkTreeIter iter;
1143    
1144     printf("selected close\n");
1145    
1146     /* the entry cannot be closed again */
1147     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
1148    
1149     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
1150    
1151     printf("gpxlist close\n");
1152    
1153     if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
1154     gpx_t *gpx = NULL;
1155     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
1156    
1157     if(gpx) gpxlist_close(appdata, GTK_LIST_STORE(model), &iter, gpx);
1158     } else {
1159     g_print ("no row selected.\n");
1160     }
1161     }
1162    
1163     static void
1164     cb_menu_remove(GtkWidget *window, gpointer data) {
1165     appdata_t *appdata = (appdata_t *)data;
1166    
1167     /* disable menu item */
1168     gtk_widget_set_sensitive(appdata->menu_remove, FALSE);
1169     gtk_widget_set_sensitive(appdata->menu_close, FALSE);
1170    
1171     GtkTreeModel *model;
1172     GtkTreeIter iter;
1173     GtkTreeSelection *selection =
1174     gtk_tree_view_get_selection(GTK_TREE_VIEW(appdata->gpxview));
1175    
1176     printf("gpxlist remove\n");
1177    
1178     if(gtk_tree_selection_get_selected(selection, &model, &iter)) {
1179     gpx_t *gpx = NULL;
1180     gtk_tree_model_get(model, &iter, GPXLIST_COL_DATA, &gpx, -1);
1181    
1182     if(gpx) gpxlist_remove(appdata, GTK_LIST_STORE(model), &iter, gpx);
1183     } else {
1184     g_print ("no row selected.\n");
1185     }
1186     }
1187    
1188     #endif // !USE_PANNABLE_AREA
1189    
1190     static void search_result_free(gpx_t *result) {
1191     printf("freeing search results\n");
1192    
1193     /* free found chain */
1194     cache_t *cache = result->cache;
1195     while(cache) {
1196     cache_t *next = cache->next;
1197     free(cache);
1198     cache = next;
1199     }
1200     free(result->name);
1201     free(result);
1202     }
1203    
1204     #define MAX_HITS 50
1205    
1206     static time_t localize_time(time_t in) {
1207     time_t ret;
1208     char *tz;
1209     struct tm *tm = localtime(&in);
1210    
1211     tz = getenv("TZ");
1212     setenv("TZ", "", 1);
1213     tzset();
1214     ret = mktime(tm);
1215     if (tz)
1216     setenv("TZ", tz, 1);
1217     else
1218     unsetenv("TZ");
1219     tzset();
1220     return ret;
1221     }
1222    
1223     static int days_ago(time_t in) {
1224     int day_in = localize_time(in) / (60*60*24);
1225     int day_now = localize_time(time(NULL)) / (60*60*24);
1226    
1227     return day_now - day_in;
1228     }
1229    
1230     gpx_t *search_do(appdata_t *appdata, gpx_t *gpx, char *phrase,
1231     int what, gboolean local) {
1232     /* walk through all caches */
1233    
1234     int hits = 0;
1235     gpx_t *found = malloc(sizeof(gpx_t));
1236     memset(found, 0, sizeof(gpx_t));
1237     cache_t **cacheP = &(found->cache);
1238    
1239     if(what & SEARCH_FINDS) {
1240     time_t loc_now = localize_time(time(NULL));
1241     printf("now: %ld days since 1/1/1970, days hour is %ld\n",
1242     loc_now/(60*60*24), loc_now%(60*60*24)/(60*60));
1243     }
1244    
1245     while(gpx && hits < MAX_HITS) {
1246    
1247     /* we need all notes ... */
1248     if(what & SEARCH_FINDS) {
1249     notes_load_all(appdata, gpx);
1250     gpx->notes_loaded = TRUE;
1251     }
1252    
1253     cache_t *cache = gpx->cache;
1254    
1255     while(cache && hits < MAX_HITS) {
1256     gboolean hit = FALSE;
1257    
1258     if(what & SEARCH_FINDS) {
1259     if(cache->notes && cache->notes->found ) {
1260     int days = days_ago(cache->notes->ftime);
1261    
1262     if(cache->id)
1263     printf("find of %s is %d days ago\n", cache->id, days);
1264    
1265     if(days <= appdata->search_days)
1266     hit = 1;
1267     }
1268     } else if(cache->id && (what & SEARCH_ID) &&
1269     strcasestr(cache->id, phrase))
1270     hit = 1;
1271     else if(cache->name && (what & SEARCH_NAME) &&
1272     strcasestr(cache->name, phrase))
1273     hit = 1;
1274     else if(cache->short_description && (what & SEARCH_DESC) &&
1275     strcasestr(cache->short_description, phrase))
1276     hit = 1;
1277     else if(cache->long_description && (what & SEARCH_DESC) &&
1278     strcasestr(cache->long_description, phrase))
1279     hit = 1;
1280     else if(cache->owner && (what & SEARCH_OWNER) &&
1281     strcasestr(cache->owner, phrase))
1282     hit = 1;
1283    
1284     if(hit) {
1285     /* chain a copy of this cache structure into the found list */
1286     *cacheP = malloc(sizeof(cache_t));
1287     memcpy(*cacheP, cache, sizeof(cache_t));
1288     (*cacheP)->next = NULL;
1289     cacheP = &((*cacheP)->next);
1290     hits++;
1291     }
1292     cache = cache->next;
1293     }
1294    
1295     if(!local) gpx = gpx->next;
1296     else gpx = NULL; /* local search within one gpx only */
1297     }
1298    
1299     found->name = strdup(_("Search results"));
1300    
1301     return found;
1302     }
1303    
1304     typedef struct {
1305     appdata_t *appdata;
1306     GtkWidget *entry, *spinner;
1307     GtkWidget *in_id, *in_name, *in_desc, *in_owner, *in_finds;
1308     } search_context_t;
1309    
1310     static void callback_finds_toggled(GtkWidget *widget, gpointer data ) {
1311     search_context_t *context = (search_context_t*)data;
1312    
1313     gboolean in_finds = gtk_toggle_button_get_active(
1314     GTK_TOGGLE_BUTTON(context->in_finds));
1315    
1316     gtk_widget_set_sensitive(context->entry, !in_finds);
1317     gtk_widget_set_sensitive(context->in_id, !in_finds);
1318     gtk_widget_set_sensitive(context->in_name, !in_finds);
1319     gtk_widget_set_sensitive(context->in_desc, !in_finds);
1320     gtk_widget_set_sensitive(context->in_owner, !in_finds);
1321     gtk_widget_set_sensitive(context->spinner, in_finds);
1322     }
1323    
1324     static void
1325     cb_menu_search(GtkWidget *window, gpointer data) {
1326     appdata_t *appdata = (appdata_t *)data;
1327    
1328     search_context_t context;
1329     memset(&context, 0, sizeof(search_context_t));
1330     context.appdata = appdata;
1331    
1332     GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Enter search phrase"),
1333     GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
1334     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1335     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1336     NULL);
1337    
1338     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1339     gtk_label_new(_("Search in:")));
1340    
1341     GtkWidget *table = gtk_table_new(2, 2, TRUE);
1342     gtk_table_set_col_spacing(GTK_TABLE(table), 0, 8);
1343    
1344     context.in_id = gtk_check_button_new_with_label(_("Waypoint IDs"));
1345     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_id),
1346     appdata->search & SEARCH_ID);
1347     gtk_table_attach_defaults(GTK_TABLE(table), context.in_id, 0, 1, 0, 1);
1348    
1349     context.in_name = gtk_check_button_new_with_label(_("Names"));
1350     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_name),
1351     appdata->search & SEARCH_NAME);
1352     gtk_table_attach_defaults(GTK_TABLE(table), context.in_name, 1, 2, 0, 1);
1353    
1354     context.in_desc = gtk_check_button_new_with_label(_("Descriptions"));
1355     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_desc),
1356     appdata->search & SEARCH_DESC);
1357     gtk_table_attach_defaults(GTK_TABLE(table), context.in_desc, 0, 1, 1, 2);
1358    
1359     context.in_owner = gtk_check_button_new_with_label(_("Owner"));
1360     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_owner),
1361     appdata->search & SEARCH_OWNER);
1362     gtk_table_attach_defaults(GTK_TABLE(table), context.in_owner, 1, 2, 1, 2);
1363    
1364     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
1365    
1366     /* -------------------------------------------------------------- */
1367    
1368     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1369     gtk_label_new(_("Search for:")));
1370     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1371     context.entry = gtk_entry_new());
1372     if(appdata->search_str)
1373     gtk_entry_set_text(GTK_ENTRY(context.entry), appdata->search_str);
1374    
1375     /* -------------------------------------------------------------- */
1376    
1377     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1378     gtk_hseparator_new());
1379    
1380     GtkWidget *hbox = gtk_hbox_new(FALSE, 5);
1381    
1382     context.in_finds = gtk_check_button_new_with_label(_("Search finds for"));
1383     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.in_finds),
1384     appdata->search & SEARCH_FINDS);
1385     gtk_box_pack_start_defaults(GTK_BOX(hbox), context.in_finds);
1386     g_signal_connect(G_OBJECT(context.in_finds), "toggled",
1387     G_CALLBACK(callback_finds_toggled), &context);
1388    
1389     #ifndef USE_MAEMO
1390     GtkObject *adj = gtk_adjustment_new(appdata->search_days, 0, 99, 1, 10, 10);
1391     context.spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
1392     #else
1393     context.spinner = hildon_number_editor_new(0, 99);
1394     hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(context.spinner),
1395     appdata->search_days);
1396     #endif
1397     gtk_box_pack_start_defaults(GTK_BOX(hbox), context.spinner);
1398    
1399     gtk_box_pack_start_defaults(GTK_BOX(hbox), gtk_label_new(_("days")));
1400    
1401     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1402    
1403     /* -------------------------------------------------------------- */
1404    
1405     gtk_widget_show_all(dialog);
1406     callback_finds_toggled(NULL, &context);
1407    
1408     if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
1409     char *p = strdup(gtk_entry_get_text(GTK_ENTRY(context.entry)));
1410    
1411     /* update saved search string */
1412     if(appdata->search_str) free(appdata->search_str);
1413     if(strlen(p) > 0)
1414     appdata->search_str = strdup(p);
1415    
1416     #ifndef USE_MAEMO
1417     appdata->search_days = gtk_spin_button_get_value_as_int(
1418     GTK_SPIN_BUTTON(context.spinner));
1419     #else
1420     appdata->search_days = hildon_number_editor_get_value(
1421     HILDON_NUMBER_EDITOR(context.spinner));
1422     #endif
1423    
1424     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_finds)))
1425     appdata->search |= SEARCH_FINDS;
1426     else
1427     appdata->search &= ~SEARCH_FINDS;
1428    
1429     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_id)))
1430     appdata->search |= SEARCH_ID;
1431     else
1432     appdata->search &= ~SEARCH_ID;
1433    
1434     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_name)))
1435     appdata->search |= SEARCH_NAME;
1436     else
1437     appdata->search &= ~SEARCH_NAME;
1438    
1439     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_desc)))
1440     appdata->search |= SEARCH_DESC;
1441     else
1442     appdata->search &= ~SEARCH_DESC;
1443    
1444     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context.in_owner)))
1445     appdata->search |= SEARCH_OWNER;
1446     else
1447     appdata->search &= ~SEARCH_OWNER;
1448    
1449     gtk_widget_destroy(dialog);
1450    
1451     /* don't search if we are asked to search for nothing */
1452     if(((appdata->search & (SEARCH_ID|SEARCH_NAME|SEARCH_DESC|SEARCH_OWNER)) &&
1453     strlen(p) > 0) || (appdata->search & SEARCH_FINDS)) {
1454    
1455     printf("Search for %s (flags = %x)...\n", p, appdata->search);
1456    
1457 harbaum 128 #if !defined(USE_BREAD_CRUMB_TRAIL) && !defined(BCT)
1458 harbaum 12 gpx_t *found =
1459 harbaum 11 search_do(appdata, appdata->gpx, p, appdata->search, FALSE);
1460 harbaum 1
1461     /* do search result dialog here ... */
1462 harbaum 12 cachelist_dialog(appdata, found);
1463 harbaum 11 #ifndef USE_STACKABLE_WINDOW
1464 harbaum 12 search_result_free(found);
1465     #else
1466     appdata->search_results = found;
1467 harbaum 11 #endif
1468 harbaum 1 #else
1469 harbaum 11 gpx_t *found = NULL;
1470    
1471 harbaum 1 if(appdata->cur_gpx)
1472     found = search_do(appdata, appdata->cur_gpx, p, appdata->search, TRUE);
1473     else
1474     found = search_do(appdata, appdata->gpx, p, appdata->search, FALSE);
1475    
1476     gtk_container_remove(GTK_CONTAINER(appdata->vbox), appdata->cur_view);
1477     appdata->cur_view = cachelist_create(appdata, found, NULL);
1478     gtk_box_pack_start_defaults(GTK_BOX(appdata->vbox), appdata->cur_view);
1479     gtk_widget_show_all(appdata->vbox);
1480     crumb_add(appdata, found->name,
1481     appdata->cur_gpx?CRUMB_SEARCH_GPX:CRUMB_SEARCH_GLOBAL, found);
1482     #endif
1483     } else
1484     printf("No valid search: \"%s\" with flags %x!\n", p, appdata->search);
1485    
1486     free(p);
1487     } else
1488     gtk_widget_destroy(dialog);
1489     }
1490    
1491 harbaum 40 static void on_window_destroy (GtkWidget *widget, gpointer data);
1492 harbaum 1
1493     #ifndef USE_MAEMO
1494     static void
1495     cb_menu_quit(GtkWidget *window, gpointer data) {
1496     on_window_destroy(window, data);
1497     }
1498     #endif
1499    
1500 harbaum 2 #ifndef NO_COPY_N_PASTE
1501 harbaum 1 static void
1502     cb_menu_cut(GtkWidget *widget, gpointer data) {
1503     appdata_t *appdata = (appdata_t*)data;
1504    
1505     if(appdata->active_buffer) {
1506     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1507     gtk_text_buffer_cut_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1508     appdata->clipboard, TRUE);
1509     } else
1510     printf("cut: ERROR, not a text buffer\n");
1511     } else
1512     printf("cut: ERROR, no active buffer\n");
1513     }
1514    
1515     static void
1516     cb_menu_copy(GtkWidget *widget, gpointer data) {
1517     appdata_t *appdata = (appdata_t*)data;
1518    
1519     if(appdata->active_buffer) {
1520     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1521     gtk_text_buffer_copy_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1522     appdata->clipboard);
1523     } else if(GTK_WIDGET_TYPE(appdata->active_buffer) == gtk_html_get_type()) {
1524     printf("copy from html buffer\n");
1525     html_copy_to_clipboard(appdata);
1526     } else
1527     printf("copy: ERROR, not a text nor a html buffer\n");
1528     } else
1529     printf("copy: ERROR, no active buffer\n");
1530     }
1531    
1532     static void
1533     cb_menu_paste(GtkWidget *widget, gpointer data) {
1534     appdata_t *appdata = (appdata_t*)data;
1535    
1536     if(appdata->active_buffer) {
1537     if(GTK_WIDGET_TYPE(appdata->active_buffer) == GTK_TYPE_TEXT_BUFFER) {
1538     gtk_text_buffer_paste_clipboard(GTK_TEXT_BUFFER(appdata->active_buffer),
1539     appdata->clipboard, NULL, TRUE);
1540     } else
1541     printf("paste: ERROR, not a text buffer\n");
1542     } else
1543     printf("paste: ERROR, no active buffer\n");
1544     }
1545 harbaum 2 #endif
1546 harbaum 1
1547 harbaum 6 static void
1548     cb_menu_export_log(GtkWidget *widget, gpointer data) {
1549     appdata_t *appdata = (appdata_t*)data;
1550     notes_log_export(appdata);
1551     }
1552 harbaum 5
1553 harbaum 122 #ifdef ENABLE_MAEMO_MAPPER
1554 harbaum 6 static void
1555     cb_menu_export_mmpoi(GtkWidget *widget, gpointer data) {
1556     appdata_t *appdata = (appdata_t*)data;
1557     mmpoi_export(appdata);
1558     }
1559     #endif
1560 harbaum 5
1561 harbaum 6 static void
1562     cb_menu_export_garmin(GtkWidget *widget, gpointer data) {
1563     appdata_t *appdata = (appdata_t*)data;
1564     garmin_export(appdata);
1565 harbaum 1 }
1566    
1567 harbaum 32 #ifdef ENABLE_OSM_GPS_MAP
1568 harbaum 6 static void
1569 harbaum 32 cb_menu_map(GtkWidget *window, gpointer data) {
1570     map((appdata_t *)data);
1571     }
1572     #endif
1573    
1574     static void
1575 harbaum 6 cb_menu_geomath(GtkWidget *window, gpointer data) {
1576     geomath_dialog((appdata_t *)data);
1577     }
1578 harbaum 5
1579 harbaum 6 static void
1580     cb_menu_geotext(GtkWidget *window, gpointer data) {
1581     geotext_dialog((appdata_t *)data);
1582 harbaum 1 }
1583    
1584 harbaum 6 static void
1585     cb_menu_precpos(GtkWidget *window, gpointer data) {
1586     precise_position((appdata_t *)data);
1587 harbaum 1 }
1588    
1589 harbaum 6 #ifdef USE_STACKABLE_WINDOW
1590 harbaum 30 typedef struct {
1591     char *label, *desc;
1592     GtkSignalFunc activate_cb;
1593     } menu_entry_t;
1594 harbaum 6
1595 harbaum 30 typedef struct {
1596     const char *title;
1597     const menu_entry_t *menu;
1598     int len;
1599     } submenu_t;
1600 harbaum 3
1601 harbaum 30 #define COLUMNS 1
1602 harbaum 4
1603 harbaum 30 void on_submenu_entry_clicked(GtkButton *button, GtkWidget *menu) {
1604 harbaum 5
1605 harbaum 30 /* force closing of submenu dialog */
1606     gtk_dialog_response(GTK_DIALOG(menu), GTK_RESPONSE_NONE);
1607     gtk_widget_hide(menu);
1608    
1609     /* let gtk clean up */
1610     while(gtk_events_pending())
1611     gtk_main_iteration();
1612 harbaum 11 }
1613    
1614 harbaum 30 static GtkWidget *app_submenu_create(appdata_t *appdata,
1615     const submenu_t *submenu) {
1616 harbaum 5
1617 harbaum 30 /* create a oridinary dialog box */
1618     GtkWidget *dialog = gtk_dialog_new();
1619     gtk_window_set_title(GTK_WINDOW(dialog), _(submenu->title));
1620     gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
1621     gtk_window_set_transient_for(GTK_WINDOW(dialog),
1622     GTK_WINDOW(appdata->window));
1623     gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
1624 harbaum 5
1625 harbaum 30 GtkWidget *table = gtk_table_new(submenu->len/COLUMNS, COLUMNS, TRUE);
1626     int x = 0, y = 0;
1627 harbaum 11
1628 harbaum 30 const menu_entry_t *menu_entries = submenu->menu;
1629     while(menu_entries->label) {
1630     GtkWidget *button = NULL;
1631 harbaum 21
1632 harbaum 30 button = hildon_button_new_with_text(
1633 harbaum 6 HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH,
1634     HILDON_BUTTON_ARRANGEMENT_VERTICAL,
1635 harbaum 30 _(menu_entries->label), _(menu_entries->desc));
1636 harbaum 5
1637 harbaum 31 /* try to center both texts */
1638     hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.5, 0.5);
1639     hildon_button_set_value_alignment(HILDON_BUTTON(button), 0.5, 0.5);
1640 harbaum 6
1641 harbaum 31 g_signal_connect(button, "clicked",
1642     G_CALLBACK(on_submenu_entry_clicked), dialog);
1643    
1644     g_signal_connect(button, "clicked",
1645     menu_entries->activate_cb, appdata);
1646    
1647 harbaum 30 gtk_table_attach_defaults(GTK_TABLE(table), button, x, x+1, y, y+1);
1648    
1649     x++;
1650     if(x == COLUMNS) { x = 0; y++; }
1651 harbaum 3
1652 harbaum 30 menu_entries++;
1653     }
1654 harbaum 20
1655 harbaum 30 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
1656    
1657     return dialog;
1658 harbaum 3 }
1659    
1660 harbaum 30 /* popup the dialog shaped submenu */
1661     static void submenu_popup(GtkWidget *menu) {
1662     gtk_widget_show_all(menu);
1663     gtk_dialog_run(GTK_DIALOG(menu));
1664     gtk_widget_hide(menu);
1665     }
1666    
1667     static void submenu_cleanup(GtkWidget *menu) {
1668     gtk_widget_destroy(menu);
1669     }
1670    
1671     static const menu_entry_t submenu_export_entries[] = {
1672 harbaum 122 #ifdef ENABLE_MAEMO_MAPPER
1673 harbaum 30 { "Export to Maemo Mapper" , "Save a Maemo Mapper POI file",
1674     G_CALLBACK(cb_menu_export_mmpoi) },
1675 harbaum 122 #endif
1676 harbaum 30 { "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 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
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 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
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 harbaum 122 #ifdef ENABLE_MAEMO_MAPPER
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 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
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 harbaum 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
2048 harbaum 1 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 harbaum 126 #ifdef USE_BREAD_CRUMB_TRAIL
2180 harbaum 1 hildon_bread_crumb_trail_push_text(HILDON_BREAD_CRUMB_TRAIL(appdata->bct),
2181     name, crumb, (GDestroyNotify)crumb_back);
2182 harbaum 126 #else
2183 harbaum 128 bct_push_text(appdata->bct, name, crumb, (GDestroyNotify)crumb_back);
2184 harbaum 126 #endif
2185 harbaum 1 }
2186     #endif // USE_BREAD_CRUMB_TRAIL
2187    
2188     void main_after_settings_redraw(appdata_t *appdata, int flags) {
2189 harbaum 11 printf("main after settings redraw\n");
2190    
2191     if(!appdata->cur_view) {
2192     printf("no active view\n");
2193     return;
2194     }
2195    
2196 harbaum 1 /* a cache screen cannot be changed from the settings and thus doesn't */
2197     /* need to be redrawn */
2198     if(appdata->cur_cache) {
2199     printf("No redraw in cache view required\n");
2200     return;
2201     }
2202    
2203     int redraw = 0; // nothing to redraw
2204    
2205     if(appdata->search_results) {
2206     if((appdata->cur_items != appdata->cachelist_items) || flags)
2207     redraw = 1;
2208     } else {
2209     if(!appdata->cur_gpx) {
2210     if(appdata->cur_items != appdata->gpxlist_items)
2211     redraw = 2; // redraw gpxlist
2212     } else {
2213     if((appdata->cur_items != appdata->cachelist_items) || flags)
2214     redraw = 3; // redraw cachelist
2215     }
2216     }
2217    
2218     if(redraw) {
2219 harbaum 11 GtkWidget *container = appdata->vbox;
2220    
2221     #ifdef USE_STACKABLE_WINDOW
2222     HildonWindowStack *stack = hildon_window_stack_get_default();
2223     container = hildon_window_stack_peek(stack);
2224     #endif
2225    
2226     gtk_container_remove(GTK_CONTAINER(container), appdata->cur_view);
2227 harbaum 1 switch(redraw) {
2228     case 1:
2229     appdata->cur_view = cachelist_create(appdata,
2230     appdata->search_results, NULL);
2231     break;
2232     case 2:
2233     appdata->cur_view = gpxlist_create_view_and_model(appdata, NULL);
2234     break;
2235     case 3:
2236     appdata->cur_view = cachelist_create(appdata,
2237     appdata->cur_gpx, NULL);
2238     break;
2239     }
2240    
2241 harbaum 11 #ifdef USE_STACKABLE_WINDOW
2242     if(container != appdata->vbox)
2243     gtk_container_add(GTK_CONTAINER(container), appdata->cur_view);
2244     else
2245     #endif
2246     gtk_box_pack_start_defaults(GTK_BOX(container), appdata->cur_view);
2247    
2248     gtk_widget_show_all(container);
2249 harbaum 1 }
2250     }
2251    
2252     int main(int argc, char *argv[]) {
2253     appdata_t appdata;
2254    
2255     /* init appdata */
2256     memset(&appdata, 0, sizeof(appdata));
2257    
2258     printf("Using locale for %s in %s\n", PACKAGE, LOCALEDIR);
2259    
2260     setlocale(LC_ALL, "");
2261     bindtextdomain(PACKAGE, LOCALEDIR);
2262     bind_textdomain_codeset(PACKAGE, "UTF-8");
2263     textdomain(PACKAGE);
2264    
2265     /* prepare thread system */
2266     g_thread_init(NULL);
2267    
2268     gtk_init (&argc, &argv);
2269    
2270     #ifdef USE_MAEMO
2271     printf("Installing osso context for \"org.harbaum." APP "\"\n");
2272     appdata.osso_context = osso_initialize("org.harbaum."APP,
2273     VERSION, TRUE, NULL);
2274     if(appdata.osso_context == NULL) {
2275     fprintf(stderr, "error initiating osso context\n");
2276     }
2277    
2278 harbaum 122 #ifdef ENABLE_MAEMO_MAPPER
2279 harbaum 1 dbus_register(&appdata);
2280     #endif
2281 harbaum 122 #endif
2282 harbaum 1
2283     icons_init();
2284    
2285     if(!gnome_vfs_init()) {
2286     g_error("Gnome VFS init failed\n");
2287     }
2288    
2289     #ifdef USE_MAEMO
2290     /* Create the hildon program and setup the title */
2291     appdata.program = HILDON_PROGRAM(hildon_program_get_instance());
2292     g_set_application_name("GPXView");
2293    
2294     /* Create HildonWindow and set it to HildonProgram */
2295     #ifdef USE_STACKABLE_WINDOW
2296     appdata.window = HILDON_WINDOW(hildon_stackable_window_new());
2297     #else
2298     appdata.window = HILDON_WINDOW(hildon_window_new());
2299     #endif
2300     hildon_program_add_window(appdata.program, appdata.window);
2301     #else
2302     /* Create a Window. */
2303     appdata.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2304     /* Set a decent default size for the window. */
2305 harbaum 129 gtk_window_set_default_size(GTK_WINDOW(appdata.window), 640, 480);
2306 harbaum 1 #endif
2307    
2308 harbaum 12 #if MAEMO_VERSION_MAJOR == 5
2309 harbaum 1 gtk_window_set_title(GTK_WINDOW(appdata.window), "GPXView");
2310 harbaum 12 #endif
2311    
2312 harbaum 1 g_signal_connect(G_OBJECT(appdata.window), "destroy",
2313     G_CALLBACK(on_window_destroy), &appdata);
2314    
2315     g_signal_connect(G_OBJECT(appdata.window), "key_press_event",
2316     G_CALLBACK(on_window_key_press), &appdata);
2317    
2318     appdata.vbox = gtk_vbox_new(FALSE, 2);
2319     gtk_container_add(GTK_CONTAINER(appdata.window), appdata.vbox);
2320 harbaum 3 #ifndef USE_STACKABLE_WINDOW
2321 harbaum 1 menu_create(&appdata);
2322 harbaum 3 #else
2323     hildon_window_set_app_menu(HILDON_WINDOW(appdata.window),
2324     menu_create(&appdata, MENU_GPXLIST));
2325     #endif
2326 harbaum 1
2327     #ifdef USE_BREAD_CRUMB_TRAIL
2328     appdata.bct = hildon_bread_crumb_trail_new();
2329    
2330     gtk_box_pack_start(GTK_BOX(appdata.vbox), appdata.bct, FALSE,FALSE,0);
2331    
2332     hildon_bread_crumb_trail_clear(HILDON_BREAD_CRUMB_TRAIL(appdata.bct));
2333 harbaum 126 #else
2334 harbaum 128 #ifdef BCT
2335 harbaum 126 /* on non-hildon machines we use some custom made breadcrumbtrail */
2336     /* replacement */
2337 harbaum 128 appdata.bct = bct_new();
2338 harbaum 126 gtk_box_pack_start(GTK_BOX(appdata.vbox), appdata.bct, FALSE,FALSE,0);
2339 harbaum 1 #endif
2340 harbaum 126 #endif
2341 harbaum 1
2342 harbaum 128 #if defined(USE_BREAD_CRUMB_TRAIL) || defined(BCT)
2343     crumb_add(&appdata, "GPX", CRUMB_GPXLIST, NULL);
2344     #endif
2345    
2346 harbaum 1 /* wait for main gui to appear */
2347     gtk_widget_show_all(GTK_WIDGET(appdata.window));
2348     while(gtk_events_pending())
2349     gtk_main_iteration();
2350    
2351     appdata.gconf_client = gconf_client_get_default();
2352     gconf_load_state(&appdata);
2353     gps_init(&appdata);
2354    
2355     appdata.cur_view = gpxlist_create_view_and_model(&appdata, NULL);
2356     gtk_box_pack_start_defaults(GTK_BOX(appdata.vbox), appdata.cur_view);
2357    
2358     gtk_widget_show_all(GTK_WIDGET(appdata.window));
2359     gtk_main();
2360    
2361     cleanup(&appdata);
2362    
2363     return 0;
2364     }