Contents of /trunk/src/garmin_export.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 199 - (hide annotations)
Thu Nov 19 13:33:35 2009 UTC (14 years, 6 months ago) by harbaum
File MIME type: text/plain
File size: 9709 byte(s)
Minor stuff
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of GPXView.
5     *
6     * GPXView is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * GPXView is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include "gpxview.h"
21     #include <sqlite3.h>
22    
23     #include <libxml/parser.h>
24     #include <libxml/tree.h>
25    
26     #if !defined(LIBXML_TREE_ENABLED) || !defined(LIBXML_OUTPUT_ENABLED)
27     #error "libxml doesn't support required tree or output"
28     #endif
29    
30     typedef struct {
31     GtkWidget *dialog;
32     appdata_t *appdata;
33     GtkWidget *path_label, *ignore_found;
34     GtkWidget *info_label;
35     gpx_t *gpx;
36     } export_context_t;
37    
38     /* add a cache to the chain of caches to be exported */
39     static void chain_cache(gpx_t *gpx, cache_t *cache) {
40     cache_t **cur = &gpx->cache;
41    
42     /* search end of chain */
43     while(*cur) {
44     if(strcmp(cache->id, (*cur)->id) == 0)
45     return;
46    
47     cur = &(*cur)->next;
48     }
49    
50     *cur = malloc(sizeof(cache_t));
51     if(!(*cur)) return;
52    
53     memcpy(*cur, cache, sizeof(cache_t));
54     (*cur)->next = NULL;
55     }
56    
57     static gpx_t *export_list_create(appdata_t *appdata) {
58     gpx_t *gpx = g_new0(gpx_t,1);
59     if(!gpx) return gpx;
60    
61     gpx_t *lgpx = appdata->gpx;
62     while(lgpx) {
63     /* make sure all notes are loaded */
64     if(!lgpx->notes_loaded) {
65     notes_load_all(appdata, lgpx);
66     lgpx->notes_loaded = TRUE;
67     }
68    
69     cache_t *cache = lgpx->cache;
70     while(cache) {
71     if(cache->notes && cache->notes->override)
72     chain_cache(gpx, cache);
73    
74     cache = cache->next;
75     }
76     lgpx = lgpx->next;
77     }
78    
79     return gpx;
80     }
81    
82     static void export_list_free(gpx_t *gpx) {
83     printf("freeing export list\n");
84    
85     cache_t *cache = gpx->cache;
86     while(cache) {
87     cache_t *tmp = cache;
88     cache = cache->next;
89     free(tmp);
90     }
91     free(gpx);
92     }
93    
94     static int export_list_count(appdata_t *appdata, gpx_t *gpx) {
95     int cnt = 0;
96    
97     cache_t *cache = gpx->cache;
98     while(cache) {
99     if(!appdata->garmin_ign_found ||
100     (appdata->garmin_ign_found && !cache->notes->found))
101     cnt++;
102    
103     cache = cache->next;
104     }
105     return cnt;
106     }
107    
108     static void on_browse(GtkWidget *widget, gpointer data) {
109     GtkWidget *dialog;
110    
111     export_context_t *context = (export_context_t*)data;
112    
113     printf("Browse\n");
114    
115     #ifdef USE_MAEMO
116     dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(context->dialog),
117     GTK_FILE_CHOOSER_ACTION_SAVE);
118     #else
119     dialog = gtk_file_chooser_dialog_new(_("Save garmin GPX"),
120     GTK_WINDOW(context->dialog),
121     GTK_FILE_CHOOSER_ACTION_SAVE,
122     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
123 harbaum 198 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
124 harbaum 1 NULL);
125     #endif
126    
127     printf("set filename <%s>\n", context->appdata->garmin_path);
128    
129     if(!g_file_test(context->appdata->garmin_path, G_FILE_TEST_EXISTS)) {
130     char *last_sep = strrchr(context->appdata->garmin_path, '/');
131     if(last_sep) {
132     *last_sep = 0; // seperate path from file
133    
134     /* the user just created a new document */
135     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
136     context->appdata->garmin_path);
137     gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), last_sep+1);
138    
139     /* restore full filename */
140     *last_sep = '/';
141     }
142     } else
143     gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
144     context->appdata->garmin_path);
145    
146     if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
147     gchar *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
148     if(name) {
149     free(context->appdata->garmin_path);
150     context->appdata->garmin_path = strdup(name);
151     gtk_label_set_text(GTK_LABEL(context->path_label),
152     context->appdata->garmin_path);
153     }
154     }
155    
156     gtk_widget_destroy(dialog);
157     }
158    
159     /* Our usual callback function */
160     static void export_update(GtkWidget *widget, gpointer data) {
161     export_context_t *context = (export_context_t *)data;
162    
163     if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(context->ignore_found)))
164     context->appdata->garmin_ign_found = TRUE;
165     else
166     context->appdata->garmin_ign_found = FALSE;
167    
168     char str[256];
169     snprintf(str, sizeof(str),
170     _("This will export the overridden coordinates of %d "
171     "caches into a GPX waypoint file suitable for garmin "
172     "GPS units."), export_list_count(context->appdata, context->gpx));
173    
174     gtk_label_set_text(GTK_LABEL(context->info_label), str);
175     }
176    
177     void garmin_export(appdata_t *appdata) {
178     char *old_garmin_path = strdup(appdata->garmin_path);
179    
180     export_context_t context;
181     memset(&context, 0, sizeof(export_context_t));
182     context.appdata = appdata;
183     context.gpx = export_list_create(appdata);
184    
185     printf("export garmin data\n");
186    
187     /* --------- do confirmation dialog ----------- */
188     context.dialog = gtk_dialog_new_with_buttons(_("Garmin waypoint export"),
189     GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
190     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
191     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
192     NULL);
193    
194     #if defined(USE_MAEMO) && defined(HILDON_HELP)
195     hildon_help_dialog_help_enable(GTK_DIALOG(context.dialog),
196     HELP_ID_GARMIN, appdata->osso_context);
197     #endif
198    
199     GtkWidget *vbox = gtk_vbox_new(FALSE,2);
200    
201     gtk_box_pack_start_defaults(GTK_BOX(vbox),
202     context.ignore_found = gtk_check_button_new_with_label(
203     _("Ignore found caches")));
204     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(context.ignore_found),
205     appdata->garmin_ign_found);
206     /* Connect the "clicked" signal of the button to our callback */
207     gtk_signal_connect (GTK_OBJECT(context.ignore_found), "clicked",
208     GTK_SIGNAL_FUNC(export_update), (gpointer)&context);
209    
210     context.info_label = gtk_label_new("");
211     gtk_label_set_line_wrap_mode(GTK_LABEL(context.info_label),PANGO_WRAP_WORD);
212     gtk_label_set_line_wrap(GTK_LABEL(context.info_label), TRUE);
213     gtk_misc_set_alignment(GTK_MISC(context.info_label), 0.f, 0.5f);
214     gtk_box_pack_start_defaults(GTK_BOX(vbox), context.info_label);
215    
216     export_update(NULL, &context);
217    
218     /* ------------------ path/file ------------------ */
219     gtk_box_pack_start_defaults(GTK_BOX(vbox), gtk_hseparator_new());
220    
221     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
222     GtkWidget *label = gtk_label_new(_("Export to:"));
223     gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE,0);
224     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
225 harbaum 7 GtkWidget *button = gtk_button_new_with_label(_("Browse"));
226 harbaum 199 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
227     hildon_gtk_widget_set_theme_size(button,
228     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
229     #endif
230 harbaum 1 gtk_signal_connect(GTK_OBJECT(button), "clicked",
231     GTK_SIGNAL_FUNC(on_browse), (gpointer)&context);
232     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE,0);
233     gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox);
234    
235     context.path_label = gtk_label_new(appdata->garmin_path);
236     gtk_misc_set_alignment(GTK_MISC(context.path_label), 0.f, 0.5f);
237     gtk_label_set_ellipsize(GTK_LABEL(context.path_label),
238     PANGO_ELLIPSIZE_MIDDLE);
239     gtk_box_pack_start_defaults(GTK_BOX(vbox), context.path_label);
240    
241     /* ----------------------------------- */
242    
243     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox), vbox);
244    
245     gtk_widget_show_all(context.dialog);
246    
247     if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) {
248     /* remove existing database */
249     remove(appdata->garmin_path);
250    
251     if(checkdir(appdata->garmin_path) != 0)
252     errorf(_("Unable to access or create output directory!"));
253     else {
254    
255     if(checkdir(appdata->garmin_path) != 0) {
256     errorf(_("Unable to create export path!"));
257     } else {
258    
259     LIBXML_TEST_VERSION;
260    
261     xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0");
262     xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "gpx");
263     xmlDocSetRootElement(doc, root_node);
264    
265     /* add all waypoints */
266     cache_t *cache = context.gpx->cache;
267     while(cache) {
268     notes_t *notes = cache->notes;
269     g_assert(notes);
270    
271     if(!appdata->garmin_ign_found ||
272     (appdata->garmin_ign_found && !notes->found)) {
273    
274     xmlNodePtr wpt_node =
275     xmlNewChild(root_node, NULL, BAD_CAST "wpt", NULL);
276    
277     /* make sure no invalid position gets saved */
278     char str[32];
279     g_ascii_dtostr(str, sizeof(str), notes->pos.lat);
280     xmlNewProp(wpt_node, BAD_CAST "lat", BAD_CAST str);
281     g_ascii_dtostr(str, sizeof(str), notes->pos.lon);
282     xmlNewProp(wpt_node, BAD_CAST "lon", BAD_CAST str);
283    
284     int len = strlen(cache->id) + strlen(" - ") +
285     strlen(cache->name) + 1;
286     char *name = malloc(len);
287     snprintf(name, len, "%s - %s", cache->id, cache->name);
288     xmlNewChild(wpt_node, NULL, BAD_CAST "name", BAD_CAST name);
289     free(name);
290     xmlNewChild(wpt_node, NULL, BAD_CAST "sym", BAD_CAST "Pin, Blue");
291     xmlNewChild(wpt_node, NULL, BAD_CAST "desc", BAD_CAST notes->text);
292     }
293    
294     cache = cache->next;
295     }
296    
297     /* write everything and free it */
298     printf("writing %s\n", appdata->garmin_path);
299     xmlSaveFormatFileEnc(appdata->garmin_path, doc, "UTF-8", 1);
300     xmlFreeDoc(doc);
301     xmlCleanupParser();
302     }
303     }
304     } else {
305     /* restore old garmin_path, in case it has been altered */
306     /* but not been used */
307     free(appdata->garmin_path);
308     appdata->garmin_path = strdup(old_garmin_path);
309     }
310    
311     gtk_widget_destroy(context.dialog);
312     export_list_free(context.gpx);
313     free(old_garmin_path);
314     }