Parent Directory | Revision Log
File selection fremantleized
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 *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 | /* Our usual callback function */ |
109 | static void export_update(GtkWidget *widget, gpointer data) { |
110 | export_context_t *context = (export_context_t *)data; |
111 | |
112 | if(check_button_get_active(context->ignore_found)) |
113 | context->appdata->garmin_ign_found = TRUE; |
114 | else |
115 | context->appdata->garmin_ign_found = FALSE; |
116 | |
117 | char str[256]; |
118 | snprintf(str, sizeof(str), |
119 | _("This will export the overridden coordinates of %d " |
120 | "caches into a GPX waypoint file suitable for garmin " |
121 | "GPS units."), export_list_count(context->appdata, context->gpx)); |
122 | |
123 | gtk_label_set_text(GTK_LABEL(context->info_label), str); |
124 | } |
125 | |
126 | void garmin_export(appdata_t *appdata) { |
127 | char *old_garmin_path = strdup(appdata->garmin_path); |
128 | |
129 | export_context_t context; |
130 | memset(&context, 0, sizeof(export_context_t)); |
131 | context.appdata = appdata; |
132 | context.gpx = export_list_create(appdata); |
133 | |
134 | printf("export garmin data\n"); |
135 | |
136 | /* --------- do confirmation dialog ----------- */ |
137 | context.dialog = gtk_dialog_new_with_buttons(_("Garmin waypoint export"), |
138 | GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL, |
139 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, |
140 | GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, |
141 | NULL); |
142 | |
143 | #if defined(USE_MAEMO) && defined(HILDON_HELP) |
144 | hildon_help_dialog_help_enable(GTK_DIALOG(context.dialog), |
145 | HELP_ID_GARMIN, appdata->osso_context); |
146 | #endif |
147 | |
148 | GtkWidget *vbox = gtk_vbox_new(FALSE,2); |
149 | |
150 | gtk_box_pack_start_defaults(GTK_BOX(vbox), |
151 | context.ignore_found = check_button_new_with_label( |
152 | _("Ignore found caches"))); |
153 | check_button_set_active(context.ignore_found, |
154 | appdata->garmin_ign_found); |
155 | /* Connect the "clicked" signal of the button to our callback */ |
156 | gtk_signal_connect (GTK_OBJECT(context.ignore_found), "clicked", |
157 | GTK_SIGNAL_FUNC(export_update), (gpointer)&context); |
158 | |
159 | context.info_label = gtk_label_new(""); |
160 | gtk_label_set_line_wrap_mode(GTK_LABEL(context.info_label),PANGO_WRAP_WORD); |
161 | gtk_label_set_line_wrap(GTK_LABEL(context.info_label), TRUE); |
162 | gtk_misc_set_alignment(GTK_MISC(context.info_label), 0.f, 0.5f); |
163 | gtk_box_pack_start_defaults(GTK_BOX(vbox), context.info_label); |
164 | |
165 | export_update(NULL, &context); |
166 | |
167 | /* ------------------ path/file ------------------ */ |
168 | gtk_box_pack_start_defaults(GTK_BOX(vbox), gtk_hseparator_new()); |
169 | |
170 | gtk_box_pack_start_defaults(GTK_BOX(vbox), |
171 | export_file(_("Save garmin GPX"), &appdata->garmin_path)); |
172 | |
173 | /* ----------------------------------- */ |
174 | |
175 | gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox), vbox); |
176 | |
177 | gtk_widget_show_all(context.dialog); |
178 | |
179 | if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) { |
180 | /* remove existing database */ |
181 | remove(appdata->garmin_path); |
182 | |
183 | if(checkdir(appdata->garmin_path) != 0) |
184 | errorf(_("Unable to access or create output directory!")); |
185 | else { |
186 | |
187 | if(checkdir(appdata->garmin_path) != 0) { |
188 | errorf(_("Unable to create export path!")); |
189 | } else { |
190 | |
191 | LIBXML_TEST_VERSION; |
192 | |
193 | xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
194 | xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "gpx"); |
195 | xmlDocSetRootElement(doc, root_node); |
196 | |
197 | /* add all waypoints */ |
198 | cache_t *cache = context.gpx->cache; |
199 | while(cache) { |
200 | notes_t *notes = cache->notes; |
201 | g_assert(notes); |
202 | |
203 | if(!appdata->garmin_ign_found || |
204 | (appdata->garmin_ign_found && !notes->found)) { |
205 | |
206 | xmlNodePtr wpt_node = |
207 | xmlNewChild(root_node, NULL, BAD_CAST "wpt", NULL); |
208 | |
209 | /* make sure no invalid position gets saved */ |
210 | char str[32]; |
211 | g_ascii_dtostr(str, sizeof(str), notes->pos.lat); |
212 | xmlNewProp(wpt_node, BAD_CAST "lat", BAD_CAST str); |
213 | g_ascii_dtostr(str, sizeof(str), notes->pos.lon); |
214 | xmlNewProp(wpt_node, BAD_CAST "lon", BAD_CAST str); |
215 | |
216 | int len = strlen(cache->id) + strlen(" - ") + |
217 | strlen(cache->name) + 1; |
218 | char *name = malloc(len); |
219 | snprintf(name, len, "%s - %s", cache->id, cache->name); |
220 | xmlNewChild(wpt_node, NULL, BAD_CAST "name", BAD_CAST name); |
221 | free(name); |
222 | xmlNewChild(wpt_node, NULL, BAD_CAST "sym", BAD_CAST "Pin, Blue"); |
223 | xmlNewChild(wpt_node, NULL, BAD_CAST "desc", BAD_CAST notes->text); |
224 | } |
225 | |
226 | cache = cache->next; |
227 | } |
228 | |
229 | /* write everything and free it */ |
230 | printf("writing %s\n", appdata->garmin_path); |
231 | xmlSaveFormatFileEnc(appdata->garmin_path, doc, "UTF-8", 1); |
232 | xmlFreeDoc(doc); |
233 | xmlCleanupParser(); |
234 | } |
235 | } |
236 | } else { |
237 | /* restore old garmin_path, in case it has been altered */ |
238 | /* but not been used */ |
239 | free(appdata->garmin_path); |
240 | appdata->garmin_path = strdup(old_garmin_path); |
241 | } |
242 | |
243 | gtk_widget_destroy(context.dialog); |
244 | export_list_free(context.gpx); |
245 | free(old_garmin_path); |
246 | } |