void osm_upload(appdata_t *appdata, osm_t *osm, project_t *project) { printf("starting upload\n"); /* upload config and confirmation dialog */ /* count nodes */ osm_dirty_t dirty; memset(&dirty, 0, sizeof(dirty)); const node_t *node = osm->node; while(node) { object_counter(OSM_BASE(node), &dirty.nodes); node = node->next; } printf("nodes: new %2d, dirty %2d, deleted %2d\n", dirty.nodes.added, dirty.nodes.dirty, dirty.nodes.deleted); /* count ways */ const way_t *way = osm->way; while(way) { object_counter(OSM_BASE(way), &dirty.ways); way = way->next; } printf("ways: new %2d, dirty %2d, deleted %2d\n", dirty.ways.added, dirty.ways.dirty, dirty.ways.deleted); /* count relations */ const relation_t *relation = osm->relation; while(relation) { object_counter(OSM_BASE(relation), &dirty.relations); relation = relation->next; } printf("relations: new %2d, dirty %2d, deleted %2d\n", dirty.relations.added, dirty.relations.dirty, dirty.relations.deleted); GtkWidget *dialog = misc_dialog_new(MISC_DIALOG_MEDIUM, _("Upload to OSM"), GTK_WINDOW(appdata->window), GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); GtkWidget *table = gtk_table_new(4, 5, TRUE); table_attach_label_c(table, _("Total"), 1, 2, 0, 1); table_attach_label_c(table, _("New"), 2, 3, 0, 1); table_attach_label_c(table, _("Modified"), 3, 4, 0, 1); table_attach_label_c(table, _("Deleted"), 4, 5, 0, 1); int row = 1; table_attach_label_l(table, _("Nodes:"), 0, 1, row, row + 1); table_insert_count(table, &dirty.nodes, row++); table_attach_label_l(table, _("Ways:"), 0, 1, row, row + 1); table_insert_count(table, &dirty.ways, row++); table_attach_label_l(table, _("Relations:"), 0, 1, row, row + 1); table_insert_count(table, &dirty.relations, row++); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), table, FALSE, FALSE, 0); /* ------------------------------------------------------ */ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), gtk_hseparator_new(), FALSE, FALSE, 0); /* ------- add username and password entries ------------ */ table = gtk_table_new(2, 2, FALSE); table_attach_label_l(table, _("Username:"******"Password:"******"Please add a comment"), -1); /* disable ok button until user edited the comment */ gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT, FALSE); g_signal_connect(G_OBJECT(buffer), "changed", G_CALLBACK(callback_buffer_modified), dialog); #ifndef FREMANTLE GtkWidget *view = gtk_text_view_new_with_buffer(buffer); #else GtkWidget *view = hildon_text_view_new(); hildon_text_view_set_buffer(HILDON_TEXT_VIEW(view), buffer); #endif gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD); gtk_text_view_set_editable(GTK_TEXT_VIEW(view), TRUE); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 2 ); gtk_text_view_set_right_margin(GTK_TEXT_VIEW(view), 2 ); g_object_set_data(G_OBJECT(view), "first_click", GINT_TO_POINTER(TRUE)); g_signal_connect(G_OBJECT(view), "focus-in-event", G_CALLBACK(cb_focus_in), buffer); gtk_container_add(GTK_CONTAINER(scrolled_win), view); gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrolled_win); gtk_widget_show_all(dialog); if(GTK_RESPONSE_ACCEPT != gtk_dialog_run(GTK_DIALOG(dialog))) { printf("upload cancelled\n"); gtk_widget_destroy(dialog); return; } printf("clicked ok\n"); /* retrieve username and password */ g_free(appdata->settings->username); appdata->settings->username = g_strdup(gtk_entry_get_text(GTK_ENTRY(uentry))); g_free(appdata->settings->password); appdata->settings->password = g_strdup(gtk_entry_get_text(GTK_ENTRY(pentry))); /* osm upload itself also has a gui */ osm_upload_context_t *context = g_new0(osm_upload_context_t, 1); context->appdata = appdata; context->osm = osm; context->project = project; /* add proxy settings if required */ if(appdata->settings) context->proxy = appdata->settings->proxy; /* fetch comment from dialog */ GtkTextIter start, end; gtk_text_buffer_get_start_iter(buffer, &start); gtk_text_buffer_get_end_iter(buffer, &end); char *text = gtk_text_buffer_get_text(buffer, &start, &end, FALSE); context->comment = g_strdup(text); gtk_widget_destroy(dialog); project_save(GTK_WIDGET(appdata->window), project); context->dialog = misc_dialog_new(MISC_DIALOG_LARGE,_("Uploading"), GTK_WINDOW(appdata->window), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL); gtk_dialog_set_response_sensitive(GTK_DIALOG(context->dialog), GTK_RESPONSE_CLOSE, FALSE); /* ------- main ui element is this text view --------------- */ GtkWidget *scrolled_window = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); context->log.buffer = gtk_text_buffer_new(NULL); context->log.view = gtk_text_view_new_with_buffer(context->log.buffer); gtk_text_view_set_editable(GTK_TEXT_VIEW(context->log.view), FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(context->log.view), FALSE); gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(context->log.view), GTK_WRAP_WORD); gtk_container_add(GTK_CONTAINER(scrolled_window), context->log.view); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_window), GTK_SHADOW_IN); gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context->dialog)->vbox), scrolled_window); gtk_widget_show_all(context->dialog); /* server url should not end with a slash */ if(project->rserver && project->rserver[strlen(project->rserver)-1] == '/') { printf("removing trailing slash\n"); project->rserver[strlen(project->rserver)-1] = 0; } appendf(&context->log, NULL, _("Log generated by %s v%s using API 0.6\n"), PACKAGE, VERSION); appendf(&context->log, NULL, _("User comment: %s\n"), context->comment); /* check if server name contains string "0.5" and adjust it */ if(project->rserver && strstr(project->rserver, "0.5") != NULL) { strstr(project->rserver, "0.5")[2] = '6'; appendf(&context->log, NULL, _("Adjusting server name to v0.6\n")); } appendf(&context->log, NULL, _("Uploading to %s\n"), project->server); /* create a new changeset */ gchar *cred; if(osm_create_changeset(context, &cred)) { /* check for dirty entries */ appendf(&context->log, NULL, _("Uploading nodes:\n")); osm_upload_nodes(context, cred); appendf(&context->log, NULL, _("Uploading ways:\n")); osm_upload_ways(context, cred); appendf(&context->log, NULL, _("Uploading relations:\n")); osm_upload_relations(context, cred); appendf(&context->log, NULL, _("Deleting relations:\n")); osm_delete_relations(context, cred); appendf(&context->log, NULL, _("Deleting ways:\n")); osm_delete_ways(context, cred); appendf(&context->log, NULL, _("Deleting nodes:\n")); osm_delete_nodes(context, cred); /* close changeset */ osm_close_changeset(context, cred); } appendf(&context->log, NULL, _("Upload done.\n")); gboolean reload_map = FALSE; if(project->data_dirty) { appendf(&context->log, NULL, _("Server data has been modified.\n")); appendf(&context->log, NULL, _("Downloading updated osm data ...\n")); if(osm_download(context->dialog, appdata->settings, project)) { appendf(&context->log, NULL, _("Download successful!\n")); appendf(&context->log, NULL, _("The map will be reloaded.\n")); project->data_dirty = FALSE; reload_map = TRUE; } else appendf(&context->log, NULL, _("Download failed!\n")); project_save(context->dialog, project); if(reload_map) { /* this kind of rather brute force reload is useful as the moment */ /* after the upload is a nice moment to bring everything in sync again. */ /* we basically restart the entire map with fresh data from the server */ /* and the diff will hopefully be empty (if the upload was successful) */ appendf(&context->log, NULL, _("Reloading map ...\n")); if(!diff_is_clean(appdata->osm, FALSE)) { appendf(&context->log, COLOR_ERR, _("*** DIFF IS NOT CLEAN ***\n")); appendf(&context->log, COLOR_ERR, _("Something went wrong during upload,\n")); appendf(&context->log, COLOR_ERR, _("proceed with care!\n")); } /* redraw the entire map by destroying all map items and redrawing them */ appendf(&context->log, NULL, _("Cleaning up ...\n")); diff_save(appdata->project, appdata->osm); map_clear(appdata, MAP_LAYER_OBJECTS_ONLY); osm_free(appdata->osm); appendf(&context->log, NULL, _("Loading OSM ...\n")); appdata->osm = osm_parse(appdata->project->path, appdata->project->osm, &appdata->icon); appendf(&context->log, NULL, _("Applying diff ...\n")); diff_restore(appdata, appdata->project, appdata->osm); appendf(&context->log, NULL, _("Painting ...\n")); map_paint(appdata); appendf(&context->log, NULL, _("Done!\n")); } } /* tell the user that he can stop waiting ... */ appendf(&context->log, NULL, _("Process finished.\n")); gtk_dialog_set_response_sensitive(GTK_DIALOG(context->dialog), GTK_RESPONSE_CLOSE, TRUE); gtk_dialog_run(GTK_DIALOG(context->dialog)); gtk_widget_destroy(context->dialog); g_free(context->comment); g_free(context); }
int main(int argc, char **argv) { int result = 0; if(argc != 4) return EINVAL; xmlInitParser(); const std::string osm_path = argv[1]; assert_cmpnum(osm_path[osm_path.size() - 1], '/'); map_state_t dummystate; project_t project(dummystate, argv[2], osm_path); project.osmFile = argv[2] + std::string(".osm"); bool b = project.parse_osm(); if(!b) { std::cerr << "cannot open " << argv[1] << argv[2] << ": " << strerror(errno) << std::endl; return 1; } osm_t::ref osm = project.osm; assert(osm); assert_cmpnum(osm->uploadPolicy, osm_t::Upload_Blocked); assert(osm->sanity_check().isEmpty()); const relation_t * const r255 = osm->relation_by_id(296255); assert(r255 != nullptr); assert_cmpnum(r255->flags, 0); assert_cmpnum(r255->members.size(), 165); assert_cmpnum(r255->tags.asMap().size(), 8); const node_t * const n72 = osm->node_by_id(638499572); assert_cmpnum(n72->tags.asMap().size(), 4); const object_t r255m572(const_cast<node_t *>(n72)); std::vector<member_t>::const_iterator r255it = r255->find_member_object(r255m572); assert(r255it != r255->members.end()); assert(r255it->role != nullptr); assert_cmpstr(r255it->role, "stop"); const relation_t * const r66316 = osm->relation_by_id(66316); assert(r66316 != nullptr); object_t rmember(object_t::RELATION_ID, 296255); assert(!rmember.is_real()); const std::vector<member_t>::const_iterator r66316it = r66316->find_member_object(rmember); assert(r66316it != r66316->members.end()); // the child relation exists, so it should be stored as real ref assert(r66316it->object.is_real()); assert_cmpnum(10, osm->nodes.size()); assert_cmpnum(3, osm->ways.size()); assert_cmpnum(4, osm->relations.size()); assert(osm->is_clean(true)); assert(project.diff_file_present()); unsigned int flags = project.diff_restore(); assert_cmpnum(flags, DIFF_RESTORED | DIFF_HAS_HIDDEN); verify_diff(osm); xmlString rel_str(r255->generate_xml("42")); printf("%s\n", rel_str.get()); rel_str.reset(n72->generate_xml("42")); printf("%s\n", rel_str.get()); char tmpdir[] = "/tmp/osm2go-diff_restore-XXXXXX"; if(mkdtemp(tmpdir) == nullptr) { std::cerr << "cannot create temporary directory" << std::endl; result = 1; } else { // create an empty directoy std::string bpath = tmpdir + std::string("/") + argv[2]; const std::string osmpath = bpath + '/' + argv[2] + ".osm"; mkdir(bpath.c_str(), 0755); bpath.erase(bpath.rfind('/') + 1); // and create a new project from that std::unique_ptr<project_t> sproject(new project_t(dummystate, argv[2], bpath)); // CAUTION: osm is shared between the projects now sproject->osm.reset(osm.get()); // the directory is empty, there can't be any diff flags = sproject->diff_restore(); assert_cmpnum(flags, DIFF_NONE_PRESENT); // should not do anything bad diff_restore(sproject, nullptr); sproject->diff_save(); bpath += argv[2]; std::string bdiff = bpath; std::string no_diff = bpath; bpath += '/'; bpath += argv[2]; bpath += '.'; bpath += "diff"; bdiff += "/backup.diff"; assert(sproject->diff_file_present()); assert_cmpnum(rename(bpath.c_str(), bdiff.c_str()), 0); // having backup.diff should still count as being present assert(sproject->diff_file_present()); no_diff += "/no.diff"; assert_cmpnum(rename(bdiff.c_str(), no_diff.c_str()), 0); assert(!sproject->diff_file_present()); // saving without OSM data should just do nothing sproject->osm.release(); // CAUTION: end of sharing sproject->diff_save(); assert(!sproject->diff_file_present()); // put the OSM data into this directory const std::string origosmpath = project.path + project.osmFile; symlink(origosmpath.c_str(), osmpath.c_str()); sproject->osmFile = project.osmFile; bool pvalid = sproject->parse_osm(); assert(pvalid); assert(sproject->osm); // now create a diff file dummy fdguard fd(open(bpath.c_str(), O_CREAT | O_WRONLY, 0600)); assert(fd.valid()); { fdguard none(-1); none.swap(fd); } assert(sproject->diff_file_present()); sproject->diff_save(); assert(!sproject->diff_file_present()); assert_cmpnum(rename(no_diff.c_str(), bdiff.c_str()), 0); flags = sproject->diff_restore(); assert_cmpnum(flags, DIFF_RESTORED | DIFF_HAS_HIDDEN); verify_diff(osm); unlink(osmpath.c_str()); unlink(bdiff.c_str()); bpath.erase(bpath.rfind('/')); rmdir(bpath.c_str()); bpath.erase(bpath.rfind('/')); rmdir(bpath.c_str()); } test_osmChange(osm, argv[3]); xmlCleanupParser(); return result; }