--- a/application/davcontroller.c Wed Nov 27 18:53:11 2024 +0100 +++ b/application/davcontroller.c Thu Nov 28 18:03:12 2024 +0100 @@ -44,6 +44,7 @@ DavBrowser* davbrowser_create(UiObject *toplevel) { DavBrowser *doc = ui_document_new(sizeof(DavBrowser)); UiContext *ctx = ui_document_context(doc); + CxMempool *mp = ui_cx_mempool(ctx); doc->window = toplevel; doc->ctx = ctx; @@ -52,6 +53,7 @@ doc->navstack_pos = 0; doc->dav_queue = ui_threadpool_create(1); + cxMempoolRegister(mp, doc->dav_queue, (cx_destructor_func)ui_threadpool_destroy); doc->res_open_inprogress = cxHashMapCreate(ctx->allocator, CX_STORE_POINTERS, 4); @@ -871,12 +873,16 @@ -DavResourceViewer* dav_resourceviewer_create(DavSession *sn, const char *path, DavResourceViewType type) { +DavResourceViewer* dav_resourceviewer_create(UiObject *toplevel, DavSession *sn, const char *path, DavResourceViewType type) { DavResourceViewer *doc = ui_document_new(sizeof(DavResourceViewer)); UiContext *ctx = ui_document_context(doc); + CxMempool *mp = ui_cx_mempool(ctx); + doc->obj = toplevel; doc->ctx = ctx; doc->sn = dav_session_clone(sn); + doc->dav_queue = ui_threadpool_create(1); + cxMempoolRegister(mp, doc->dav_queue, (cx_destructor_func)ui_threadpool_destroy); doc->path = strdup(path); doc->type = type; @@ -896,6 +902,13 @@ doc->info_etag = ui_string_new(ctx, "info_etag"); doc->info_size = ui_string_new(ctx, "info_size"); + doc->property_type = ui_int_new(ctx, NULL); + doc->property_ns = ui_string_new(ctx, NULL); + doc->property_name = ui_string_new(ctx, NULL); + doc->property_nsdef = ui_string_new(ctx, NULL); + doc->property_value = ui_text_new(ctx, NULL); + doc->property_errormsg = ui_string_new(ctx, NULL); + return doc; } @@ -1017,8 +1030,13 @@ DavPropertyList *prop = ui_malloc(doc->ctx, sizeof(DavPropertyList)); prop->ns = properties[i].ns ? ui_strdup(doc->ctx, properties[i].ns) : NULL; prop->name = ui_strdup(doc->ctx, properties[i].name); + prop->value_simplified = NULL; + prop->value_full = NULL; + prop->update = FALSE; + prop->isnew = FALSE; DavXmlNode *xval = dav_get_property_ns(res, prop->ns, prop->name); + prop->xml = xval; if(xval) { if(dav_xml_isstring(xval)) { char *value = dav_xml_getstring(xval); @@ -1090,6 +1108,7 @@ static void uithr_upload_text_finished(UiEvent *event, void *data) { ResourceViewerUploadFile *upload = data; + ui_object_unref(event->obj); if(upload->error) { cxmutstr errormsg = cx_asprintf("Upload failed: %d", upload->sn->error); // TODO: add full error message @@ -1098,31 +1117,129 @@ ui_set_group(event->obj->ctx, RESOURCEVIEWER_STATE_MODIFIED); } - dav_session_destroy(upload->sn); - free(upload->path); free(upload->text.ptr); free(upload); } +static int jobthr_store_properties(void *data) { + DavResourceViewer *res = data; + res->error = dav_store(res->current); + return 0; +} + +static void uithr_store_properties_finished(UiEvent *event, void *data) { + DavResourceViewer *res = data; + ui_object_unref(event->obj); + if(res->error) { + cxmutstr errormsg = cx_asprintf("Proppatch failed: %d", res->sn->error); // TODO: add full error message + ui_dialog(event->obj, .title = "Error", .content = errormsg.ptr, .closebutton_label = "OK"); + free(errormsg.ptr); + ui_set_group(event->obj->ctx, RESOURCEVIEWER_STATE_MODIFIED); + res->properties_modified = TRUE; + } else { + CxList *properties = res->properties->data; + CxIterator i = cxListIterator(properties); + cx_foreach(DavPropertyList *, prop, i) { + prop->update = FALSE; + prop->isnew = FALSE; + } + } +} + void dav_resourceviewer_save(UiObject *ui, DavResourceViewer *res) { if(res->type == DAV_RESOURCE_VIEW_TEXT) { - DavSession *newsn = dav_session_clone(res->current->session); ResourceViewerUploadFile *upload = malloc(sizeof(ResourceViewerUploadFile)); upload->ui = ui; - upload->sn = newsn; - upload->path = strdup(res->current->path); + upload->sn = res->sn; + upload->path = res->current->path; char *text = ui_get(res->text); - size_t textlen = strlen(text); - upload->text = cx_strdup(cx_strn(text, textlen)); - ui_job(ui, jobthr_upload_text, upload, uithr_upload_text_finished, upload); - ui_unset_group(ui->ctx, RESOURCEVIEWER_STATE_MODIFIED); + upload->text = cx_strdup(cx_str(text)); + ui_object_ref(res->obj); + ui_threadpool_job(res->dav_queue, ui, jobthr_upload_text, upload, uithr_upload_text_finished, upload); } + + if(res->properties_modified) { + CxList *properties = res->properties->data; + CxIterator i = cxListIterator(properties); + cx_foreach(DavPropertyList *, prop, i) { + if(prop->update) { + if(prop->value_full) { + // text + dav_set_string_property_ns(res->current, prop->ns, prop->name, prop->value_full); + } else { + // xml + dav_set_property_ns(res->current, prop->ns, prop->name, prop->xml); + } + } + } + + ui_object_ref(res->obj); + ui_threadpool_job(res->dav_queue, ui, jobthr_store_properties, res, uithr_store_properties_finished, res); + } + + ui_unset_group(ui->ctx, RESOURCEVIEWER_STATE_MODIFIED); } void dav_resourceviewer_destroy(DavResourceViewer *res) { } +void dav_resourceviewer_property_remove(DavResourceViewer *res, DavPropertyList *prop) { + if(!prop->isnew) { + dav_remove_property_ns(res->current, prop->ns, prop->name); + ui_set_group(res->obj->ctx, RESOURCEVIEWER_STATE_MODIFIED); + res->properties_modified = TRUE; + } + + CxList *properties = res->properties->data; + cxListFindRemove(properties, prop); + ui_free(res->ctx, prop->ns); + ui_free(res->ctx, prop->name); + ui_free(res->ctx, prop->value_simplified); + ui_free(res->ctx, prop->value_full); + // prop->xml freed by DavSession + ui_free(res->ctx, prop); + ui_list_update(res->properties); +} + +void dav_resourceviewer_property_update_text(DavResourceViewer *res, DavPropertyList *prop, const char *text) { + ui_free(res->ctx, prop->value_simplified); + ui_free(res->ctx, prop->value_full); + prop->xml = NULL; + prop->value_full = ui_strdup(res->ctx, text); + prop->value_simplified = NULL; + prop->update = TRUE; + + ui_set_group(res->obj->ctx, RESOURCEVIEWER_STATE_MODIFIED); + res->properties_modified = TRUE; + ui_list_update(res->properties); +} + +void dav_resourceviewer_property_update_xml(DavResourceViewer *res, DavPropertyList *prop, DavXmlNode *xml) { + +} + +void dav_resourceviewer_property_add_text(DavResourceViewer *res, const char *ns, const char *name, const char *text) { + DavPropertyList *prop = ui_malloc(res->ctx, sizeof(DavPropertyList)); + prop->ns = ui_strdup(res->ctx, ns); + prop->name = ui_strdup(res->ctx, name); + prop->value_simplified = NULL; + prop->value_full = ui_strdup(res->ctx, text); + prop->xml = NULL; + prop->isnew = TRUE; + prop->update = TRUE; + + ui_list_append(res->properties, prop); + ui_set_group(res->obj->ctx, RESOURCEVIEWER_STATE_MODIFIED); + res->properties_modified = TRUE; + ui_list_update(res->properties); +} + +void dav_resourceviewer_property_add_xml(DavResourceViewer *res, const char *ns, const char *name, const char *nsdef, DavXmlNode *xml) { + +} + + uint64_t dav_transfer_speed(TransferProgress *progress, time_t current) { size_t bytes = progress->transferred_bytes - progress->speedtest_bytes;