Contents of /trunk/src/garmin_export.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 199 - (show 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 /*
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 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
124 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 GtkWidget *button = gtk_button_new_with_label(_("Browse"));
226 #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 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 }