Contents of /trunk/src/osm_api.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Wed Dec 10 19:50:17 2008 UTC (15 years, 4 months ago) by harbaum
File MIME type: text/plain
File size: 23756 byte(s)
Asynchronous network io
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of OSM2Go.
5 *
6 * OSM2Go 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 * OSM2Go 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 OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "appdata.h"
21
22 #include <curl/curl.h>
23 #include <curl/types.h> /* new for v7 */
24 #include <curl/easy.h> /* new for v7 */
25 #include <unistd.h>
26
27 static struct http_message_s {
28 int id;
29 char *msg;
30 } http_messages [] = {
31 { 200, "Ok" },
32 { 400, "Bad Request" },
33 { 401, "Unauthorized" },
34 { 403, "Forbidden" },
35 { 404, "Not Found" },
36 { 405, "Method Not Allowed" },
37 { 410, "Gone" },
38 { 412, "Precondition Failed" },
39 { 417, "(Expect rejected)" },
40 { 500, "Internal Server Error" },
41 { 503, "Service Unavailable" },
42 { 0, NULL }
43 };
44
45 static char *osm_http_message(int id) {
46 struct http_message_s *msg = http_messages;
47
48 while(msg->id) {
49 if(msg->id == id) return _(msg->msg);
50 msg++;
51 }
52
53 return NULL;
54 }
55
56 typedef struct {
57 appdata_t *appdata;
58 GtkWidget *dialog;
59 osm_t *osm;
60 project_t *project;
61
62 struct log_s {
63 GtkTextBuffer *buffer;
64 GtkWidget *view;
65 } log;
66
67 } osm_upload_context_t;
68
69 gboolean osm_download(GtkWidget *parent, project_t *project) {
70 printf("download osm ...\n");
71
72 char minlon[G_ASCII_DTOSTR_BUF_SIZE], minlat[G_ASCII_DTOSTR_BUF_SIZE];
73 char maxlon[G_ASCII_DTOSTR_BUF_SIZE], maxlat[G_ASCII_DTOSTR_BUF_SIZE];
74
75 g_ascii_dtostr(minlon, sizeof(minlon), project->min.lon);
76 g_ascii_dtostr(minlat, sizeof(minlat), project->min.lat);
77 g_ascii_dtostr(maxlon, sizeof(maxlon), project->max.lon);
78 g_ascii_dtostr(maxlat, sizeof(maxlat), project->max.lat);
79
80 char *url = g_strdup_printf("%s/map?bbox=%s,%s,%s,%s",
81 project->server, minlon, minlat, maxlon, maxlat);
82
83 gboolean result = net_io_download_file(parent, url, project->osm);
84
85 g_free(url);
86 return result;
87 }
88
89 typedef struct {
90 char *ptr;
91 int len;
92 } curl_data_t;
93
94 static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
95 curl_data_t *p = (curl_data_t*)stream;
96
97 // printf("request to read %d items of size %d, pointer = %p\n",
98 // nmemb, size, p->ptr);
99
100 if(nmemb*size > p->len)
101 nmemb = p->len/size;
102
103 memcpy(ptr, p->ptr, size*nmemb);
104 p->ptr += size*nmemb;
105 p->len -= size*nmemb;
106
107 return nmemb;
108 }
109
110 static size_t write_callback(void *ptr, size_t size, size_t nmemb, void *stream) {
111 curl_data_t *p = (curl_data_t*)stream;
112
113 p->ptr = g_realloc(p->ptr, p->len + size*nmemb + 1);
114 if(p->ptr) {
115 memcpy(p->ptr+p->len, ptr, size*nmemb);
116 p->len += size*nmemb;
117 p->ptr[p->len] = 0;
118 }
119 return nmemb;
120 }
121
122 static void appendf(struct log_s *log, const char *fmt, ...) {
123 va_list args;
124 va_start( args, fmt );
125 char *buf = g_strdup_vprintf(fmt, args);
126 va_end( args );
127
128 GtkTextIter end;
129 gtk_text_buffer_get_end_iter(log->buffer, &end);
130 gtk_text_buffer_insert(log->buffer, &end, buf, -1);
131
132 g_free(buf);
133
134 gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(log->view),
135 &end, 0.0, FALSE, 0, 0);
136
137 while(gtk_events_pending())
138 gtk_main_iteration();
139 }
140
141 #define MAX_TRY 5
142
143 static gboolean osm_update_item(struct log_s *log, char *xml_str,
144 char *url, char *user, item_id_t *id) {
145 int retry = MAX_TRY;
146 char buffer[CURL_ERROR_SIZE];
147
148 CURL *curl;
149 CURLcode res;
150
151 curl_data_t read_data;
152 curl_data_t write_data;
153
154 while(retry >= 0) {
155
156 if(retry != MAX_TRY)
157 appendf(log, _("Retry %d/%d "), MAX_TRY-retry, MAX_TRY-1);
158
159 /* get a curl handle */
160 curl = curl_easy_init();
161 if(!curl) {
162 appendf(log, _("CURL init error\n"));
163 return FALSE;
164 }
165
166 read_data.ptr = xml_str;
167 read_data.len = strlen(xml_str);
168 write_data.ptr = NULL;
169 write_data.len = 0;
170
171 /* we want to use our own read/write functions */
172 curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
173 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
174
175 /* enable uploading */
176 curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
177
178 /* specify target URL, and note that this URL should include a file
179 name, not only a directory */
180 curl_easy_setopt(curl, CURLOPT_URL, url);
181
182 /* now specify which file to upload */
183 curl_easy_setopt(curl, CURLOPT_READDATA, &read_data);
184
185 /* provide the size of the upload, we specicially typecast the value
186 to curl_off_t since we must be sure to use the correct data size */
187 curl_easy_setopt(curl, CURLOPT_INFILESIZE, (long)strlen(xml_str));
188
189 /* we pass our 'chunk' struct to the callback function */
190 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_data);
191
192 /* some servers don't like requests that are made without a user-agent
193 field, so we provide one */
194 curl_easy_setopt(curl, CURLOPT_USERAGENT,
195 PACKAGE "-libcurl/" VERSION);
196
197 struct curl_slist *slist=NULL;
198 slist = curl_slist_append(slist, "Expect:");
199 curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
200
201 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);
202
203 /* set user name and password for the authentication */
204 curl_easy_setopt(curl, CURLOPT_USERPWD, user);
205
206 /* Now run off and do what you've been told! */
207 res = curl_easy_perform(curl);
208
209 long response;
210 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
211
212 /* always cleanup */
213 curl_slist_free_all(slist);
214 curl_easy_cleanup(curl);
215
216 printf("reply is \"%s\"\n", write_data.ptr);
217
218 /* this will return the id on a successful create */
219 if(id && (res == 0) && (response == 200)) {
220 printf("request to parse successful reply as an id\n");
221 *id = strtoul(write_data.ptr, NULL, 10);
222 }
223
224 g_free(write_data.ptr);
225
226 if(res != 0)
227 appendf(log, _("failed: %s\n"), buffer);
228 else if(response != 200)
229 appendf(log, _("failed, code: %ld %s\n"),
230 response, osm_http_message(response));
231 else {
232 if(!id) appendf(log, _("ok\n"));
233 else appendf(log, _("ok: #%ld\n"), *id);
234 }
235
236 /* don't retry unless we had an "internal server error" */
237 if(response != 500)
238 return((res == 0)&&(response == 200));
239
240 retry--;
241 }
242
243 return FALSE;
244 }
245
246 static gboolean osm_delete_item(struct log_s *log, char *url, char *user) {
247 int retry = MAX_TRY;
248 char buffer[CURL_ERROR_SIZE];
249
250 CURL *curl;
251 CURLcode res;
252
253 while(retry >= 0) {
254
255 if(retry != MAX_TRY)
256 appendf(log, _("Retry %d/%d "), MAX_TRY-retry, MAX_TRY-1);
257
258 /* get a curl handle */
259 curl = curl_easy_init();
260 if(!curl) {
261 appendf(log, _("CURL init error\n"));
262 return FALSE;
263 }
264
265 /* no read/write functions required */
266 curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
267
268 /* specify target URL, and note that this URL should include a file
269 name, not only a directory */
270 curl_easy_setopt(curl, CURLOPT_URL, url);
271
272 /* some servers don't like requests that are made without a user-agent
273 field, so we provide one */
274 curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE "-libcurl/" VERSION);
275
276 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);
277
278 /* set user name and password for the authentication */
279 curl_easy_setopt(curl, CURLOPT_USERPWD, user);
280
281 /* Now run off and do what you've been told! */
282 res = curl_easy_perform(curl);
283
284 long response;
285 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
286
287 /* always cleanup */
288 curl_easy_cleanup(curl);
289
290 if(res != 0)
291 appendf(log, _("failed: %s\n"), buffer);
292 else if(response != 200)
293 appendf(log, _("failed, code: %ld %s\n"),
294 response, osm_http_message(response));
295 else
296 appendf(log, _("ok\n"));
297
298 /* don't retry unless we had an "internal server error" */
299 if(response != 500)
300 return((res == 0)&&(response == 200));
301
302 retry--;
303 }
304
305 return FALSE;
306 }
307
308 typedef struct {
309 struct {
310 int total, new, dirty, deleted;
311 } ways, nodes, relations;
312 } osm_dirty_t;
313
314 static GtkWidget *table_attach_label_c(GtkWidget *table, char *str,
315 int x1, int x2, int y1, int y2) {
316 GtkWidget *label = gtk_label_new(str);
317 gtk_table_attach_defaults(GTK_TABLE(table), label, x1, x2, y1, y2);
318 return label;
319 }
320
321 static GtkWidget *table_attach_label_l(GtkWidget *table, char *str,
322 int x1, int x2, int y1, int y2) {
323 GtkWidget *label = table_attach_label_c(table, str, x1, x2, y1, y2);
324 gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
325 return label;
326 }
327
328 static GtkWidget *table_attach_int(GtkWidget *table, int num,
329 int x1, int x2, int y1, int y2) {
330 char *str = g_strdup_printf("%d", num);
331 GtkWidget *label = table_attach_label_c(table, str, x1, x2, y1, y2);
332 g_free(str);
333 return label;
334 }
335
336 static void osm_delete_nodes(osm_upload_context_t *context) {
337 node_t *node = context->osm->node;
338 project_t *project = context->project;
339
340 while(node) {
341 /* make sure gui gets updated */
342 while(gtk_events_pending()) gtk_main_iteration();
343
344 if(node->flags & OSM_FLAG_DELETED) {
345 printf("deleting node on server\n");
346
347 appendf(&context->log, _("Delete node #%ld "), node->id);
348
349 char *url = g_strdup_printf("%s/node/%lu", project->server, node->id);
350 char *cred = g_strdup_printf("%s:%s",
351 context->appdata->settings->username,
352 context->appdata->settings->password);
353
354 if(osm_delete_item(&context->log, url, cred)) {
355 node->flags &= ~(OSM_FLAG_DIRTY | OSM_FLAG_DELETED);
356 project->data_dirty = TRUE;
357 }
358
359 g_free(cred);
360 }
361 node = node->next;
362 }
363 }
364
365 static void osm_upload_nodes(osm_upload_context_t *context) {
366 node_t *node = context->osm->node;
367 project_t *project = context->project;
368
369 while(node) {
370 /* make sure gui gets updated */
371 while(gtk_events_pending()) gtk_main_iteration();
372
373 if((node->flags & (OSM_FLAG_DIRTY | OSM_FLAG_NEW)) &&
374 (!(node->flags & OSM_FLAG_DELETED))) {
375 char *url = NULL;
376
377 if(node->flags & OSM_FLAG_NEW) {
378 url = g_strdup_printf("%s/node/create", project->server);
379 appendf(&context->log, _("New node "));
380 } else {
381 url = g_strdup_printf("%s/node/%lu", project->server, node->id);
382 appendf(&context->log, _("Modified node #%ld "), node->id);
383 }
384
385 /* upload this node */
386 char *xml_str = osm_generate_xml_node(context->osm, node);
387 if(xml_str) {
388 printf("uploading node %s from address %p\n", url, xml_str);
389
390 char *cred = g_strdup_printf("%s:%s",
391 context->appdata->settings->username, context->appdata->settings->password);
392 if(osm_update_item(&context->log, xml_str, url, cred,
393 (node->flags & OSM_FLAG_NEW)?&(node->id):NULL)) {
394
395 node->flags &= ~(OSM_FLAG_DIRTY | OSM_FLAG_NEW);
396 project->data_dirty = TRUE;
397 }
398 g_free(cred);
399 }
400 g_free(url);
401 }
402 node = node->next;
403 }
404 }
405
406 static void osm_delete_ways(osm_upload_context_t *context) {
407 way_t *way = context->osm->way;
408 project_t *project = context->project;
409
410 while(way) {
411 /* make sure gui gets updated */
412 while(gtk_events_pending()) gtk_main_iteration();
413
414 if(way->flags & OSM_FLAG_DELETED) {
415 printf("deleting way on server\n");
416
417 appendf(&context->log, _("Delete way #%ld "), way->id);
418
419 char *url = g_strdup_printf("%s/way/%lu", project->server, way->id);
420 char *cred = g_strdup_printf("%s:%s",
421 context->appdata->settings->username, context->appdata->settings->password);
422
423 if(osm_delete_item(&context->log, url, cred)) {
424 way->flags &= ~(OSM_FLAG_DIRTY | OSM_FLAG_DELETED);
425 project->data_dirty = TRUE;
426 }
427
428 g_free(cred);
429 }
430 way = way->next;
431 }
432 }
433
434
435 static void osm_upload_ways(osm_upload_context_t *context) {
436 way_t *way = context->osm->way;
437 project_t *project = context->project;
438
439 while(way) {
440 /* make sure gui gets updated */
441 while(gtk_events_pending()) gtk_main_iteration();
442
443 if((way->flags & (OSM_FLAG_DIRTY | OSM_FLAG_NEW)) &&
444 (!(way->flags & OSM_FLAG_DELETED))) {
445 char *url = NULL;
446
447 if(way->flags & OSM_FLAG_NEW) {
448 url = g_strdup_printf("%s/way/create", project->server);
449 appendf(&context->log, _("New way "));
450 } else {
451 url = g_strdup_printf("%s/way/%lu", project->server, way->id);
452 appendf(&context->log, _("Modified way #%ld "), way->id);
453 }
454
455 /* upload this node */
456 char *xml_str = osm_generate_xml_way(context->osm, way);
457 if(xml_str) {
458 printf("uploading way %s from address %p\n", url, xml_str);
459
460 char *cred = g_strdup_printf("%s:%s",
461 context->appdata->settings->username, context->appdata->settings->password);
462 if(osm_update_item(&context->log, xml_str, url, cred,
463 (way->flags & OSM_FLAG_NEW)?&(way->id):NULL)) {
464 way->flags &= ~(OSM_FLAG_DIRTY | OSM_FLAG_NEW);
465 project->data_dirty = TRUE;
466 }
467 g_free(cred);
468 }
469 g_free(url);
470 }
471 way = way->next;
472 }
473 }
474
475
476 static void osm_upload_relations(osm_upload_context_t *context) {
477 relation_t *relation = context->osm->relation;
478 project_t *project = context->project;
479
480 while(relation) {
481 /* make sure gui gets updated */
482 while(gtk_events_pending()) gtk_main_iteration();
483
484 if((relation->flags & (OSM_FLAG_DIRTY | OSM_FLAG_NEW)) &&
485 (!(relation->flags & OSM_FLAG_DELETED))) {
486 char *url = NULL;
487
488 if(relation->flags & OSM_FLAG_NEW) {
489 url = g_strdup_printf("%s/relation/create", project->server);
490 appendf(&context->log, _("New relation "));
491 } else {
492 url = g_strdup_printf("%s/relation/%lu", project->server,relation->id);
493 appendf(&context->log, _("Modified relation #%ld "), relation->id);
494 }
495
496 /* upload this relation */
497 char *xml_str = osm_generate_xml_relation(context->osm, relation);
498 if(xml_str) {
499 printf("uploading relation %s from address %p\n", url, xml_str);
500
501 char *cred = g_strdup_printf("%s:%s",
502 context->appdata->settings->username, context->appdata->settings->password);
503 if(osm_update_item(&context->log, xml_str, url, cred,
504 (relation->flags & OSM_FLAG_NEW)?&(relation->id):NULL)) {
505 relation->flags &= ~(OSM_FLAG_DIRTY | OSM_FLAG_NEW);
506 project->data_dirty = TRUE;
507 }
508 g_free(cred);
509 }
510 g_free(url);
511 }
512 relation = relation->next;
513 }
514 }
515
516
517 void osm_upload(appdata_t *appdata, osm_t *osm, project_t *project) {
518
519 printf("starting upload\n");
520
521 /* upload config and confirmation dialog */
522
523 /* count nodes */
524 osm_dirty_t dirty;
525 memset(&dirty, 0, sizeof(osm_dirty_t));
526
527 node_t *node = osm->node;
528 while(node) {
529 dirty.nodes.total++;
530 if(node->flags & OSM_FLAG_DELETED) dirty.nodes.deleted++;
531 else if(node->flags & OSM_FLAG_NEW) dirty.nodes.new++;
532 else if(node->flags & OSM_FLAG_DIRTY) dirty.nodes.dirty++;
533
534 node = node->next;
535 }
536 printf("nodes: new %2d, dirty %2d, deleted %2d\n",
537 dirty.nodes.new, dirty.nodes.dirty, dirty.nodes.deleted);
538
539 /* count ways */
540 way_t *way = osm->way;
541 while(way) {
542 dirty.ways.total++;
543 if(way->flags & OSM_FLAG_DELETED) dirty.ways.deleted++;
544 else if(way->flags & OSM_FLAG_NEW) dirty.ways.new++;
545 else if(way->flags & OSM_FLAG_DIRTY) dirty.ways.dirty++;
546
547 way = way->next;
548 }
549 printf("ways: new %2d, dirty %2d, deleted %2d\n",
550 dirty.ways.new, dirty.ways.dirty, dirty.ways.deleted);
551
552 /* count relations */
553 relation_t *relation = osm->relation;
554 while(relation) {
555 dirty.relations.total++;
556 if(relation->flags & OSM_FLAG_DELETED) dirty.relations.deleted++;
557 else if(relation->flags & OSM_FLAG_NEW) dirty.relations.new++;
558 else if(relation->flags & OSM_FLAG_DIRTY) dirty.relations.dirty++;
559
560 relation = relation->next;
561 }
562 printf("relations: new %2d, dirty %2d, deleted %2d\n",
563 dirty.relations.new, dirty.relations.dirty, dirty.relations.deleted);
564
565
566 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Upload to OSM"),
567 GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
568 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
569 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
570 NULL);
571
572 GtkWidget *table = gtk_table_new(4, 5, TRUE);
573
574 table_attach_label_c(table, _("Total"), 1, 2, 0, 1);
575 table_attach_label_c(table, _("New"), 2, 3, 0, 1);
576 table_attach_label_c(table, _("Modified"), 3, 4, 0, 1);
577 table_attach_label_c(table, _("Deleted"), 4, 5, 0, 1);
578
579 table_attach_label_l(table, _("Nodes:"), 0, 1, 1, 2);
580 table_attach_int(table, dirty.nodes.total, 1, 2, 1, 2);
581 table_attach_int(table, dirty.nodes.new, 2, 3, 1, 2);
582 table_attach_int(table, dirty.nodes.dirty, 3, 4, 1, 2);
583 table_attach_int(table, dirty.nodes.deleted, 4, 5, 1, 2);
584
585 table_attach_label_l(table, _("Ways:"), 0, 1, 2, 3);
586 table_attach_int(table, dirty.ways.total, 1, 2, 2, 3);
587 table_attach_int(table, dirty.ways.new, 2, 3, 2, 3);
588 table_attach_int(table, dirty.ways.dirty, 3, 4, 2, 3);
589 table_attach_int(table, dirty.ways.deleted, 4, 5, 2, 3);
590
591 table_attach_label_l(table, _("Relations:"), 0, 1, 3, 4);
592 table_attach_int(table, dirty.relations.total, 1, 2, 3, 4);
593 table_attach_int(table, dirty.relations.new, 2, 3, 3, 4);
594 table_attach_int(table, dirty.relations.dirty, 3, 4, 3, 4);
595 table_attach_int(table, dirty.relations.deleted, 4, 5, 3, 4);
596
597 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
598
599 /* ------------------------------------------------------ */
600
601 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
602 gtk_hseparator_new());
603
604 /* ------- add username and password entries ------------ */
605
606 table = gtk_table_new(2, 2, FALSE);
607 table_attach_label_l(table, _("Username:"), 0, 1, 0, 1);
608 GtkWidget *uentry = gtk_entry_new();
609 HILDON_ENTRY_NO_AUTOCAP(uentry);
610 gtk_entry_set_text(GTK_ENTRY(uentry), appdata->settings->username);
611 gtk_table_attach_defaults(GTK_TABLE(table), uentry, 1, 2, 0, 1);
612 table_attach_label_l(table, _("Password:"), 0, 1, 1, 2);
613 GtkWidget *pentry = gtk_entry_new();
614 HILDON_ENTRY_NO_AUTOCAP(pentry);
615 gtk_entry_set_text(GTK_ENTRY(pentry), appdata->settings->password);
616 gtk_entry_set_visibility(GTK_ENTRY(pentry), FALSE);
617 gtk_table_attach_defaults(GTK_TABLE(table), pentry, 1, 2, 1, 2);
618 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
619
620 gtk_widget_show_all(dialog);
621
622 if(GTK_RESPONSE_ACCEPT != gtk_dialog_run(GTK_DIALOG(dialog))) {
623 printf("upload cancelled\n");
624 gtk_widget_destroy(dialog);
625 return;
626 }
627
628 printf("clicked ok\n");
629
630 /* retrieve username and password */
631 if(appdata->settings->username)
632 g_free(appdata->settings->username);
633 appdata->settings->username =
634 g_strdup(gtk_entry_get_text(GTK_ENTRY(uentry)));
635
636 if(appdata->settings->password)
637 g_free(appdata->settings->password);
638 appdata->settings->password =
639 g_strdup(gtk_entry_get_text(GTK_ENTRY(pentry)));
640
641 gtk_widget_destroy(dialog);
642 project_save(GTK_WIDGET(appdata->window), project);
643
644 /* osm upload itself also has a gui */
645 osm_upload_context_t *context = g_new0(osm_upload_context_t, 1);
646 context->appdata = appdata;
647 context->osm = osm;
648 context->project = project;
649
650 context->dialog = gtk_dialog_new_with_buttons(_("Upload to OSM"),
651 GTK_WINDOW(appdata->window), GTK_DIALOG_MODAL,
652 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
653 gtk_dialog_set_response_sensitive(GTK_DIALOG(context->dialog),
654 GTK_RESPONSE_CLOSE, FALSE);
655
656 /* making the dialog a little wider makes it less "crowded" */
657 #ifndef USE_HILDON
658 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 480, 256);
659 #else
660 gtk_window_set_default_size(GTK_WINDOW(context->dialog), 800, 480);
661 #endif
662
663 /* ------- main ui elelent is this text view --------------- */
664
665 GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL);
666 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
667 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
668
669 context->log.buffer = gtk_text_buffer_new(NULL);
670
671 context->log.view = gtk_text_view_new_with_buffer(context->log.buffer);
672 gtk_text_view_set_editable(GTK_TEXT_VIEW(context->log.view), FALSE);
673 gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(context->log.view), FALSE);
674
675 gtk_container_add(GTK_CONTAINER(scrolled_window), context->log.view);
676 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window),
677 GTK_SHADOW_IN);
678
679 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox),
680 scrolled_window);
681 gtk_widget_show_all(context->dialog);
682
683 appendf(&context->log, _("Log generated by %s v%s using API 0.5\n"),
684 PACKAGE, VERSION);
685 appendf(&context->log, _("Uploading to %s\n"), project->server);
686
687 /* check for dirty entries */
688 appendf(&context->log, _("Uploading nodes:\n"));
689 osm_upload_nodes(context);
690 appendf(&context->log, _("Uploading ways:\n"));
691 osm_upload_ways(context);
692 appendf(&context->log, _("Uploading relations:\n"));
693 osm_upload_relations(context);
694 appendf(&context->log, _("Deleting ways:\n"));
695 osm_delete_ways(context);
696 appendf(&context->log, _("Deleting nodes:\n"));
697 osm_delete_nodes(context);
698
699
700 appendf(&context->log, _("Upload done.\n"));
701
702 gboolean reload_map = FALSE;
703 if(project->data_dirty) {
704 appendf(&context->log, _("Server data has been modified.\n"));
705 appendf(&context->log, _("Downloading updated osm data ...\n"));
706
707 if(osm_download(context->dialog, project)) {
708 appendf(&context->log, _("Download successful!\n"));
709 appendf(&context->log, _("The map will be reloaded.\n"));
710 project->data_dirty = FALSE;
711 reload_map = TRUE;
712 } else
713 appendf(&context->log, _("Download failed!\n"));
714
715 project_save(context->dialog, project);
716
717 if(reload_map) {
718 /* this kind of rather brute force reload is useful as the moment */
719 /* after the upload is a nice moment to bring everything in sync again. */
720 /* we basically restart the entire map with fresh data from the server */
721 /* and the diff will hopefully be empty (if the upload was successful) */
722
723 appendf(&context->log, _("Reloading map ...\n"));
724
725 if(!diff_is_clean(appdata->osm, FALSE)) {
726 appendf(&context->log, _(">>>>>>>> DIFF IS NOT CLEAN <<<<<<<<\n"));
727 appendf(&context->log, _("Something went wrong during upload,\n"));
728 appendf(&context->log, _("proceed with care!\n"));
729 }
730
731 /* redraw the entire map by destroying all map items and redrawing them */
732 appendf(&context->log, _("Cleaning up ...\n"));
733 diff_save(appdata->project, appdata->osm);
734 map_clear(appdata, MAP_LAYER_OBJECTS_ONLY);
735 osm_free(&appdata->icon, appdata->osm);
736
737 appendf(&context->log, _("Loading OSM ...\n"));
738 appdata->osm = osm_parse(appdata->project->osm);
739 appendf(&context->log, _("Applying diff ...\n"));
740 diff_restore(appdata, appdata->project, appdata->osm);
741 appendf(&context->log, _("Painting ...\n"));
742 map_paint(appdata);
743 appendf(&context->log, _("Done!\n"));
744 }
745 }
746
747 /* tell the user that he can stop waiting ... */
748 appendf(&context->log, _("Process finished.\n"));
749
750 gtk_dialog_set_response_sensitive(GTK_DIALOG(context->dialog),
751 GTK_RESPONSE_CLOSE, TRUE);
752
753 gtk_dialog_run(GTK_DIALOG(context->dialog));
754 gtk_widget_destroy(context->dialog);
755
756 }
757