From: Olaf Wintermann Date: Sun, 18 Jan 2026 15:07:47 +0000 (+0100) Subject: fix moving notebooks to other groups X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=9af667574bcca39078e009d1c3ca5a18f3bff95b;p=note.git fix moving notebooks to other groups --- diff --git a/application/nbconfig.c b/application/nbconfig.c index a2d4064..aa93411 100644 --- a/application/nbconfig.c +++ b/application/nbconfig.c @@ -38,10 +38,16 @@ static UiBool notebooklist_move_inprogress = FALSE; static int notebooklist_move_pos0 = 0; static int notebooklist_move_pos1 = 0; -static void* reslist_getvalue(void *data, int col) { - Resource *resource = data; +static void* reslist_getvalue(UiList *list, void *elm, int row, int col, void *userdata, UiBool *freeResult) { + NotebookConfigDialog *wdata = userdata; + Resource *resource = elm; switch(col) { case 0: { + if(resource == wdata->selected_group && wdata->selected_group_name) { + return wdata->selected_group_name; + } else if(resource == wdata->selected_notebook && wdata->selected_notebook_name) { + return wdata->selected_notebook_name; + } return resource->displayname ? resource->displayname : resource->nodename; } case 1: { @@ -58,6 +64,15 @@ static void* repolist_get_value(void *data, int col) { return repo->name; } +void nbconfig_update_list(NotebookConfigDialog *wdata, CxList *list, int index) { + if(list == wdata->groups) { + ui_list_update_row(wdata->tab1_groups, index); + ui_list_update_row(wdata->tab2_groups, index); + } else if(list == wdata->notebooks) { + ui_list_update_row(wdata->tab2_notebooks, index); + } +} + void nbconfig_update_lists(NotebookConfigDialog *wdata) { ui_list_clear(wdata->tab1_groups); ui_list_clear(wdata->tab2_groups); @@ -114,13 +129,14 @@ static void nbconfig_tab1_load_group(NotebookConfigDialog *wdata, Resource *res) static void nbconfig_tab2_load_notebook(NotebookConfigDialog *wdata, Resource *res) { Notebook *nb = res->notebook; - CxHashKey key = cx_hash_key(&res->resource_id, sizeof(res->resource_id)); - Resource *parent = cxMapGet(wdata->notebook_parents, key); ui_set(wdata->tab2_notebook_name, res->nodename); - if(parent) { - size_t index = cxListFind(wdata->groups, parent); - ui_list_setselection(wdata->tab2_groups, index); + CxIterator i = cxListIterator(wdata->groups); + cx_foreach(Resource *, parent, i) { + if(parent->resource_id == res->parent_id) { + ui_list_setselection(wdata->tab2_groups, (int)i.index); + break; + } } wdata->selected_notebook = res; @@ -142,21 +158,9 @@ static int nbconfig_list_activate_event(UiEvent *event, UiList *list, void **lis } -static void group_created(UiEvent *event, int64_t newid, int error, void *userdata) { - Resource *res = userdata; - NoteStore *store = note_store_get(); - if(store->root) { - if(!store->root->children) { - store->root->children = cxArrayListCreate(store->mp->allocator, CX_STORE_POINTERS, 8); - } - cxListAdd(store->root->children, res); - note_store_groups_updated(); - } -} - static void group_saved(UiEvent *event, int error, void *userdata) { if(error) { - fprintf(stderr, "Error: note_store_save_resource failed\n"); + fprintf(stderr, "Error: note_store_save_notebook_async failed\n"); } } @@ -166,20 +170,18 @@ static void nbconfig_group_save(NotebookConfigDialog *nbconfig) { return; } - Resource *dup = cxMapGet(nbconfig->current_names, res->nodename); + Resource *dup = cxMapGet(nbconfig->current_names, nbconfig->selected_group_name); if(dup) { - fprintf(stderr, "Name %s already in use\n", res->nodename); + fprintf(stderr, "Name %s already in use\n", nbconfig->selected_group_name); // TODO: show error in UI - // TODO: restore old name return; } - if(res->resource_id == 0) { - note_store_new_notebook_async(application_global_obj(), res, group_created, res); - } else { - note_store_update_resource_async(application_global_obj(), res, group_saved, res); - note_store_groups_updated(); - } + NoteStore *store = note_store_get(); + cxFree(store->mp->allocator, nbconfig->selected_group->nodename); + nbconfig->selected_group->nodename = cx_strdup_a(store->mp->allocator, nbconfig->selected_group_name).ptr; + + note_store_save_notebook_async(application_global_obj(), res, 0, group_saved, res); } static void nbconfig_grouplist_onselect(UiEvent *event, void *userdata) { @@ -283,22 +285,17 @@ static void nbconfig_grouplist_name_changed(UiEvent *event, void *userdata) { return; } NotebookConfigDialog *wdata = event->window; - NoteStore *store = note_store_get(); + UiContext *ctx = wdata->obj->ctx; wdata->valuechange = TRUE; if(wdata->selected_group) { char *input = ui_get(wdata->tab1_group_name); - cxFree(store->mp->allocator, wdata->selected_group->nodename); - wdata->selected_group->nodename = cx_strdup_a(store->mp->allocator, cx_str(input)).ptr; + ui_free(ctx, wdata->selected_group_name); + wdata->selected_group_name = ui_strdup(ctx, input); - UiListSelection sel = ui_list_getselection(wdata->tab1_groups); - nbconfig_update_lists(wdata); // TODO: update only single row - if(sel.count > 0) { - ui_list_setselection(wdata->tab1_groups, sel.rows[0]); - } - ui_listselection_free(sel); + nbconfig_update_list(wdata, wdata->groups, cxListFind(wdata->groups, wdata->selected_group)); Resource *dup = cxMapGet(wdata->current_names, input); if(dup) { @@ -310,22 +307,9 @@ static void nbconfig_grouplist_name_changed(UiEvent *event, void *userdata) { wdata->valuechange = FALSE; } -static void notebook_created(UiEvent *event, int64_t newid, int error, void *userdata) { - NoteStore *store = note_store_get(); - Resource *res = userdata; - Resource *parent = note_store_get_notebook_by_id(store, res->parent_id); - if(parent) { - if(!parent->children) { - parent->children = cxArrayListCreate(store->mp->allocator, CX_STORE_POINTERS, 8); - } - cxListAdd(parent->children, res); - note_store_groups_updated(); - } -} - static void notebook_saved(UiEvent *event, int error, void *userdata) { if(error) { - fprintf(stderr, "Error: note_store_save_resource failed\n"); + fprintf(stderr, "Error: note_store_save_notebook_async failed\n"); } } @@ -335,6 +319,20 @@ static void nbconfig_notebook_save(NotebookConfigDialog *nbconfig) { return; } + // check if the notebook name is unique + Resource *dup = cxMapGet(nbconfig->current_names, nbconfig->selected_notebook_name); + if(dup) { + fprintf(stderr, "Name %s already in use\n", nbconfig->selected_notebook_name); + // TODO: show error in UI + return; + } + + // update name + NoteStore *store = note_store_get(); + cxFree(store->mp->allocator, nbconfig->selected_notebook->nodename); + nbconfig->selected_notebook->nodename = cx_strdup_a(store->mp->allocator, nbconfig->selected_notebook_name).ptr; + + // update parent UiListSelection sel = ui_list_getselection(nbconfig->tab2_groups); if(sel.count == 0) { return; // shouldn't happen, maybe remove this when ui_list_getselectedindex exists @@ -344,14 +342,10 @@ static void nbconfig_notebook_save(NotebookConfigDialog *nbconfig) { return; //shouldn't happen } ui_listselection_free(sel); + int64_t prev_parent_id = res->parent_id; res->parent_id = parent->resource_id; - if(res->resource_id == 0) { - note_store_new_notebook_async(application_global_obj(), res, notebook_created, res); - } else { - note_store_update_resource_async(application_global_obj(), res, notebook_saved, res); - note_store_groups_updated(); - } + note_store_save_notebook_async(application_global_obj(), res, prev_parent_id, notebook_saved, res); } static void nbconfig_notebooklist_onselect(UiEvent *event, void *userdata) { @@ -366,9 +360,8 @@ static void nbconfig_notebooklist_onselect(UiEvent *event, void *userdata) { if(nbconfig_list_activate_event(event, wdata->tab2_notebooks, (void**)&res)) { return; } - nbconfig_tab2_load_notebook(wdata, res); - - wdata->selected_group = res; + wdata->selected_notebook = res; + nbconfig_tab2_load_notebook(wdata, res); nbconfig_build_current_names_map(wdata, res); } @@ -376,17 +369,23 @@ static void nbconfig_notebooklist_onselect(UiEvent *event, void *userdata) { static void nbconfig_notebooklist_add(UiEvent *event, void *userdata) { NotebookConfigDialog *wdata = event->window; NoteStore *store = note_store_get(); + UiContext *ctx = wdata->obj->ctx; + + Resource *parent = cxListAt(wdata->groups, 0); Resource *notebook = cxCalloc(store->mp->allocator, 1, sizeof(Resource)); notebook->notebook = cxCalloc(store->mp->allocator, 1, sizeof(Notebook)); - - if(wdata->selected_notebook) { - // TODO + if(parent) { + notebook->parent_id = parent->resource_id; } + cxListAdd(wdata->notebooks, notebook); wdata->selected_notebook = notebook; + ui_free(ctx, wdata->selected_notebook_name); + wdata->selected_notebook_name = ui_strdup(ctx, "New"); + nbconfig_update_lists(wdata); - ui_set(wdata->tab2_notebook_name, ""); + ui_set(wdata->tab2_notebook_name, "New"); ui_list_setselection(wdata->tab2_repositories, 0); ui_list_setselection(wdata->tab2_types, 0); } @@ -397,24 +396,22 @@ static void nbconfig_notebooklist_name_changed(UiEvent *event, void *userdata) { } NotebookConfigDialog *wdata = event->window; - NoteStore *store = note_store_get(); + UiContext *ctx = wdata->obj->ctx; wdata->valuechange = TRUE; if(wdata->selected_notebook) { - UiBool add_notebook = FALSE; - if(!wdata->selected_notebook->nodename) { - add_notebook = TRUE; - } else { - cxFree(store->mp->allocator, wdata->selected_notebook->nodename); - } + char *input = ui_get(wdata->tab2_notebook_name); + ui_free(ctx, wdata->selected_notebook_name); + wdata->selected_notebook_name = ui_strdup(ctx, input); - wdata->selected_notebook->nodename = cx_strdup_a(store->mp->allocator, cx_str(ui_get(wdata->tab2_notebook_name))).ptr; + nbconfig_update_list(wdata, wdata->notebooks, cxListFind(wdata->notebooks, wdata->selected_notebook)); - if(add_notebook) { - cxListAdd(wdata->notebooks, wdata->selected_notebook); + Resource *dup = cxMapGet(wdata->current_names, input); + if(dup) { + fprintf(stderr, "Name %s already in use\n", input); + // TODO: show error in UI } - nbconfig_update_lists(wdata); // TODO: update only single row } wdata->valuechange = FALSE; @@ -596,7 +593,6 @@ void notebook_config_dialog(void) { wdata->repositories = cxArrayListCreate(a, CX_STORE_POINTERS, 32); wdata->groups = cxArrayListCreate(a, CX_STORE_POINTERS, 32); wdata->notebooks = cxArrayListCreate(a, CX_STORE_POINTERS, 32); - wdata->notebook_parents = cxHashMapCreate(a, CX_STORE_POINTERS, 32); wdata->current_names = cxHashMapCreate(a, CX_STORE_POINTERS, 16); @@ -612,11 +608,6 @@ void notebook_config_dialog(void) { CxIterator k = cxListIterator(res->children); cx_foreach(Resource *, nb, k) { cxListAdd(wdata->notebooks, nb); - CxHashKey key = cx_hash_key(&nb->resource_id, sizeof(nb->resource_id)); - cxMapPut(wdata->notebook_parents, key, res); - if(!notebook1) { - notebook1 = nb; - } } } nbconfig_update_lists(wdata); @@ -634,7 +625,7 @@ void notebook_config_dialog(void) { ui_tab(obj, "Groups") { ui_hbox(obj, .margin = 10, .spacing = 10, .fill = TRUE) { ui_vbox(obj, .fill = FALSE) { - ui_listview(obj, .list = wdata->tab1_groups, .getvalue = reslist_getvalue, .fill = TRUE, .onselection = nbconfig_grouplist_onselect); + ui_listview(obj, .list = wdata->tab1_groups, .getvalue2 = reslist_getvalue, .getvalue2data = wdata, .fill = TRUE, .onselection = nbconfig_grouplist_onselect); ui_hbox(obj, .fill = FALSE) { ui_button(obj, .icon = UI_ICON_NEW_FOLDER, .onclick = nbconfig_grouplist_add); ui_button(obj, .icon = UI_ICON_DELETE, .onclick = nbconfig_grouplist_delete); @@ -661,7 +652,7 @@ void notebook_config_dialog(void) { ui_tab(obj, "Notebooks") { ui_hbox(obj, .margin = 10, .spacing = 10, .fill = TRUE) { ui_vbox(obj) { - ui_listview(obj, .list = wdata->tab2_notebooks, .getvalue = reslist_getvalue, .fill = TRUE, .onselection = nbconfig_notebooklist_onselect); + ui_listview(obj, .list = wdata->tab2_notebooks, .getvalue2 = reslist_getvalue, .getvalue2data = wdata, .fill = TRUE, .onselection = nbconfig_notebooklist_onselect); ui_hbox(obj) { ui_button(obj, .icon = UI_ICON_NEW_FOLDER, .onclick = nbconfig_notebooklist_add); ui_button(obj, .icon = UI_ICON_DELETE, .onclick = nbconfig_notebooklist_delete); @@ -672,7 +663,7 @@ void notebook_config_dialog(void) { ui_grid(obj, .columnspacing = 10, .rowspacing = 10, .fill = TRUE, .def_vfill = TRUE) { ui_rlabel(obj, .label = "Group"); - ui_dropdown(obj, .list = wdata->tab2_groups, .getvalue = reslist_getvalue); + ui_dropdown(obj, .list = wdata->tab2_groups, .getvalue2 = reslist_getvalue, .getvalue2data = wdata); ui_newline(obj); ui_rlabel(obj, .label = "Name"); diff --git a/application/nbconfig.h b/application/nbconfig.h index d7d917f..942a899 100644 --- a/application/nbconfig.h +++ b/application/nbconfig.h @@ -43,7 +43,6 @@ typedef struct NotebookConfigDialog { CxList *repositories; CxList *groups; CxList *notebooks; - CxMap *notebook_parents; UiList *tab1_groups; UiString *tab1_group_name; @@ -75,6 +74,7 @@ typedef struct NotebookConfigDialog { UiBool valuechange; } NotebookConfigDialog; +void nbconfig_update_list(NotebookConfigDialog *wdata, CxList *list, int index); void nbconfig_update_lists(NotebookConfigDialog *wdata); void nbconfig_build_current_names_map(NotebookConfigDialog *wdata, Resource *res); diff --git a/application/store.c b/application/store.c index 4c47bf8..7484d40 100644 --- a/application/store.c +++ b/application/store.c @@ -104,7 +104,7 @@ "(?, ?, ?) returning resource_id;" #define SQL_RESOURCE_SAVE \ - "update resources set nodename = ?, displayname = ?, contenttype = ? where resource_id = ? ;" + "update resources set nodename = ?, displayname = ?, contenttype = ?, parent_id = ? where resource_id = ? ;" #define SQL_NOTEBOOK_NEW \ "insert into notebooks(resource_id, position) values " \ @@ -1050,8 +1050,9 @@ static int qthr_update_resource(ExecJob *job) { } else { dbuQuerySetParamNull(q, 3); } + dbuQuerySetParamInt64(q, 4, res->parent_id); - dbuQuerySetParamInt64(q, 4, res->resource_id); + dbuQuerySetParamInt64(q, 5, res->resource_id); if(dbuQueryExec(q)) { job->error = 1; @@ -1088,6 +1089,7 @@ void note_store_update_resource_async(UiObject *obj, Resource *res, execresult_f typedef struct SaveResourceJob { NoteStore *store; Resource *res; + int64_t prev_parent_id; execresult_func resultcb; void *userdata; } SaveResourceJob; @@ -1095,6 +1097,20 @@ typedef struct SaveResourceJob { static void uithr_save_resource_finished(UiEvent *event, int error, void *userdata) { SaveResourceJob *job = userdata; if(!error) { + if(job->prev_parent_id != 0 && job->prev_parent_id != job->res->parent_id) { + // move resource to new parent + NoteStore *store = note_store_get(); + Resource *old_parent = note_store_get_notebook_by_id(store, job->prev_parent_id); + Resource *new_parent = note_store_get_notebook_by_id(store, job->res->parent_id); + if(old_parent && new_parent && old_parent->children) { + size_t i = cxListFind(old_parent->children, job->res); + cxListRemove(old_parent->children, i); + if(!new_parent->children) { + new_parent->children = cxArrayListCreate(store->mp->allocator, CX_STORE_POINTERS, 8); + } + cxListAdd(new_parent->children, job->res); + } + } note_store_groups_updated(); } if(job->resultcb) { @@ -1118,10 +1134,11 @@ static void uithr_save_new_resource_finished(UiEvent *event, int64_t newid, int uithr_save_resource_finished(event, error, userdata); } -void note_store_save_notebook_async(UiObject *obj, Resource *res, execresult_func resultcb, void *userdata) { +void note_store_save_notebook_async(UiObject *obj, Resource *res, int64_t prev_parent_id, execresult_func resultcb, void *userdata) { SaveResourceJob *job = malloc(sizeof(SaveResourceJob)); job->store = note_store_get(); job->res = res; + job->prev_parent_id = prev_parent_id; job->resultcb = resultcb; job->userdata = userdata; if(res->resource_id == 0) { diff --git a/application/store.h b/application/store.h index f1b3939..319e9c3 100644 --- a/application/store.h +++ b/application/store.h @@ -140,7 +140,7 @@ void note_store_new_resource_async(UiObject *obj, Resource *res, createresult_fu void note_store_update_resource_async(UiObject *obj, Resource *res, execresult_func resultcb, void *userdata); -void note_store_save_notebook_async(UiObject *obj, Resource *res, execresult_func resultcb, void *userdata); +void note_store_save_notebook_async(UiObject *obj, Resource *res, int64_t prev_parent_id, execresult_func resultcb, void *userdata); void note_store_delete_empty_collection_async( UiObject *obj, diff --git a/application/tests/test-store.c b/application/tests/test-store.c index c8fc54d..f48d39d 100644 --- a/application/tests/test-store.c +++ b/application/tests/test-store.c @@ -290,7 +290,7 @@ CX_TEST(test_note_store_save_notebook_async) { res0->nodename = cx_strdup_a(store->mp->allocator, "test_save_notebook_res0").ptr; int error = -1; - note_store_save_notebook_async(obj, res0, test_save_notebook_result, &error); + note_store_save_notebook_async(obj, res0, 0, test_save_notebook_result, &error); ui_exec_buffered_mainthread_calls_wait(3); CX_TEST_ASSERT(error == 0); @@ -314,7 +314,7 @@ CX_TEST(test_note_store_save_notebook_async) { ui_exec_buffered_mainthread_calls(); error = -1; - note_store_save_notebook_async(obj, res0, test_save_notebook_result, &error); + note_store_save_notebook_async(obj, res0, 0, test_save_notebook_result, &error); ui_exec_buffered_mainthread_calls_wait(3); CX_TEST_ASSERT(error == 0);