]> uap-core.de Git - note.git/commitdiff
implement note deletion
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 18 Mar 2025 19:57:30 +0000 (20:57 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Tue, 18 Mar 2025 19:57:30 +0000 (20:57 +0100)
application/application.c
application/application.h
application/menu.c
application/menu.h
application/note.c
application/note.h
application/notebook.c
application/notebook.h
application/store.c
application/store.h
application/window.c

index 6e5f4418b115608b1c856b1940f73498b7d93c91..745782b1fd89793a7177aa782bd1185b5bb01223 100644 (file)
 #include "store.h"
 #include "menu.h"
 #include "notebook.h"
+#include "note.h"
 #include "editor.h"
 
 #include <unistd.h>
 #include <limits.h>
 
 #include <cx/mempool.h>
+#include <cx/printf.h>
 
 void application_init() {
     menu_init();
@@ -130,3 +132,25 @@ void action_note_new(UiEvent *event, void *data) {
     NotebookModel *notebook = event->document;
     notebookmodel_new_note(notebook);
 }
+
+
+static void delete_result(UiEvent *event, void *data) {
+    NotebookModel *notebook = event->document;
+    if(event->intval) {
+        notebookmodel_delete_note(notebook);
+    }
+}
+
+void action_note_delete(UiEvent *event, void *data) {
+    NotebookModel *notebook = event->document;
+    Note *note = notebook->current_note;
+    cxmutstr msg = cx_asprintf("Delete note %s?", note_get_title(note));
+    ui_dialog(
+            event->obj,
+            .title = "Delete Note",
+            .content = msg.ptr,
+            .button1_label = "Delete",
+            .closebutton_label = "Cancel",
+            .result = delete_result);
+    free(msg.ptr);
+}
\ No newline at end of file
index ac28c5c1334476ff1ce9d1af014c44ca8b8e7f45..00a06fc080e5e0f141258e782aa647aa951b075c 100644 (file)
@@ -155,7 +155,7 @@ void action_go_back(UiEvent *event, void *data);
 void action_go_forward(UiEvent *event, void *data);
 
 void action_note_new(UiEvent *event, void *data);
-
+void action_note_delete(UiEvent *event, void *data);
 
 #ifdef __cplusplus
 }
index fd89f9a3f2e602024d813c14d8b05756b57dcf5d..d2d1ae0cb4f219733ce0f4a35abc9a32187a0ac3 100644 (file)
 
 #include "menu.h"
 
+static UiMenuBuilder* notelist_context_menu;
+
 void menu_init() {
-    
+    ui_contextmenu(&notelist_context_menu) {
+        ui_menuitem(.label = "New Note", .onclick = action_note_new);
+        ui_menuitem(.label = "Delete", .onclick = action_note_delete);
+    }
+}
+
+void menu_cleanup() {
+    ui_menubuilder_free(notelist_context_menu);
 }
 
 void toolbar_init() {
@@ -41,3 +50,8 @@ void toolbar_init() {
     ui_toolbar_add_default("GoForward", UI_TOOLBAR_LEFT);
     ui_toolbar_add_default("AddNote", UI_TOOLBAR_LEFT);
 }
+
+
+UiMenuBuilder* get_notelist_context_menu() {
+    return notelist_context_menu;
+}
index 66b7e5778545bd7c649c508b2855d00531ef56c9..806dd2d459606c897cbef28ca06ceed3b3f298ce 100644 (file)
@@ -38,8 +38,11 @@ extern "C" {
 #endif
 
 void menu_init();
+void menu_cleanup();
 void toolbar_init();
 
+UiMenuBuilder* get_notelist_context_menu();
+
 
 #ifdef __cplusplus
 }
index 24ae291a98e7557cc511ea9a6c9fe3a08cb09df0..52f0b7e2cca0c31ee4928bf33c5fc5eca3d4f764 100644 (file)
@@ -176,3 +176,23 @@ void note_text_style_set_code(NoteModel *note, UiBool enabled) {
         ui_set(note->textnote_code, !enabled);
     }
 }
+
+
+const char* note_get_title(Note *note) {
+    return note->title ? note->title : note->name;
+}
+
+void note_destroy(const CxAllocator *a, Note *note) {
+    cxFree(a, note->name);
+    cxFree(a, note->title);
+    cxFree(a, note->lastmodified);
+    cxFree(a, note->creationdate);
+    cxFree(a, note->contenttype);
+    cxFree(a, note->created_by);
+    cxFree(a, note->content.ptr);
+    cxFree(a, note->bin_content.ptr);
+    
+    if(note->model) {
+        // TODO: destroy model->context
+    }
+}
index fcaab320b9d7cc29ddd39a0eb24ca95a90e2e87d..c2db4173bf17f37dd479ef1e0504646a5fe1733f 100644 (file)
@@ -42,7 +42,7 @@ typedef struct TextNoteParagraphStyles {
 } TextNoteParagraphStyles;
     
 NoteModel *notemodel_current(UiObject *obj);
-    
+  
 NoteModel* notemodel_create(const CxAllocator *note_allocator);
 void notemodel_set_note(NoteModel *model, Note *note);
 
@@ -60,6 +60,9 @@ void note_text_style_set_underline(NoteModel *note, UiBool enabled);
 void note_text_style_set_code(NoteModel *note, UiBool enabled);
 
 
+const char* note_get_title(Note *note);
+void note_destroy(const CxAllocator *a, Note *note);
+
 #ifdef __cplusplus
 }
 #endif
index 55cdad2aaa7043e72122f3fdb93a13d6e7a6b23e..b2ba83184c056489bc0548f5bffeaf439a4b159e 100644 (file)
@@ -32,6 +32,8 @@
 #include "note.h"
 #include "editor.h"
 
+#include <cx/printf.h>
+
 NotebookModel* notebookmodel_create() {
     NotebookModel *model = ui_document_new(sizeof(NotebookModel));
     model->ctx = ui_document_context(model);
@@ -195,6 +197,34 @@ void notebookmodel_new_note(NotebookModel *model) {
     editor_load_markdown(new_note->model->text, cx_mutstrn("", 0));
 }
 
+typedef struct NoteDeleteOp {
+    NotebookModel *notebook;
+    Note *note;
+} NoteDeleteOp;
+
+static void note_deleted(UiEvent *event, int error, void *userdata) {
+    NotebookModel *notebook = event->document;
+    NoteDeleteOp *op = userdata;
+    
+    CxList *notes = op->notebook->notes->data;
+    size_t index = cxListFind(notes, op->note);
+    if(cxListIndexValid(notes, index)) {
+        cxListRemove(notes, index);
+        ui_list_update(op->notebook->notes);
+        note_destroy(op->notebook->current_notes_pool->allocator, op->note);
+    } else {
+        fprintf(stderr, "Error: cannot remove deleted note from list\n");
+    }
+}
+
+void notebookmodel_delete_note(NotebookModel *model) {
+    NoteDeleteOp *op = malloc(sizeof(NoteDeleteOp));
+    op->notebook = model;
+    op->note = model->current_note;
+    note_store_delete_async(model->window->obj, op->note, TRUE, note_deleted, op);
+}
+
+
 /*
  * Add the current state (notebook + note + ui options) to the navstack.
  * If the user navigated through the navstack and the current pos is not the
index 9ed6cbe479952d934021a3b394881769d513a6a9..ec7178d49fc3932c194b0d2d5ea9dc90c6c7c0a1 100644 (file)
@@ -52,6 +52,7 @@ void notebookmodel_detach_current_note(NotebookModel *model);
 Note* notebookmodel_get_note_by_id(NotebookModel *model, int64_t note_id, size_t *index);
 
 void notebookmodel_new_note(NotebookModel *model);
+void notebookmodel_delete_note(NotebookModel *model);
 
 void notebookmodel_add2navstack(NotebookModel *model);
 
index 97fb59b638b04dbae8a1d8cce1fad02fce8c6236..3d6758f60ac7f3201fd5f74d9a59aa986da95481 100644 (file)
     "content = ? " \
     "where note_id = ? ;"
 
+#define SQL_NOTE_MOVE_TO_TRASH "update notes set parent_id = ? where note_id = ? ;"
+
+#define SQL_NOTE_DELETE "delete from notes where note_id = ? ;"
+
 static DBUConnection *connection;
 
 static UiThreadpool *queue;
@@ -313,6 +317,7 @@ void note_store_reload() {
     NoteStore *store = cxMalloc(a, sizeof(NoteStore));
     store->mp = mp;
     store->root = NULL;
+    store->trash = NULL;
     
     // key: collection_id  value: Collection*
     CxMap *collection_map = cxHashMapCreate(NULL, CX_STORE_POINTERS, cxListSize(collections) + 16);
@@ -554,3 +559,46 @@ void note_store_save_note_async(UiObject *obj, Note *note, execresult_func resul
     job->error = 0;
     ui_threadpool_job(queue, obj, (ui_threadfunc)qthr_save_note, job, (ui_callback)uithr_save_note_finished, job);
 }
+
+
+typedef struct DeleteNoteJob {
+    int64_t note_id;
+    UiBool move_to_trash;
+    execresult_func resultcb;
+    void *userdata;
+    int error;
+} DeleteNoteJob;
+
+static int qthr_delete_note(DeleteNoteJob *job) {
+    DBUQuery *q = connection->createQuery(connection, NULL);
+    if(job->move_to_trash && current_store->trash) {
+        dbuQuerySetSQL(q, SQL_NOTE_MOVE_TO_TRASH);
+        dbuQuerySetParamInt64(q, 1, current_store->trash->collection_id);
+        dbuQuerySetParamInt64(q, 2, job->note_id);
+    } else {
+        dbuQuerySetSQL(q, SQL_NOTE_DELETE);
+        dbuQuerySetParamInt64(q, 1, job->note_id);
+    }
+    if(dbuQueryExec(q)) {
+        job->error = 1;
+    }
+    dbuQueryFree(q);
+    return 0;
+}
+
+static void uithr_save_delete_finished(UiEvent *event, DeleteNoteJob *job) {
+    if(job->resultcb) {
+        job->resultcb(event, job->error, job->userdata);
+    }
+    free(job);
+}
+
+void note_store_delete_async(UiObject *obj, Note *note, UiBool move_to_trash, execresult_func resultcb, void *userdata) {
+    DeleteNoteJob *job = malloc(sizeof(DeleteNoteJob));
+    job->note_id = note->note_id;
+    job->move_to_trash = move_to_trash;
+    job->resultcb = resultcb;
+    job->userdata = userdata;
+    job->error = 0;
+    ui_threadpool_job(queue, obj, (ui_threadfunc)qthr_delete_note, job, (ui_callback)uithr_save_delete_finished, job);
+}
index 1c96af7f7ea8b02f7b2ca5c1a35721d8416ba344..629b3b3826cbf8281e0eedc66fb25080769d6c40 100644 (file)
@@ -43,6 +43,7 @@ extern "C" {
 typedef struct NoteStore {
     CxMempool *mp;
     Collection *root;
+    Collection *trash;
 } NoteStore;
     
 typedef struct AsyncListResult {
@@ -89,6 +90,8 @@ void note_store_get_note_content_async(UiObject *obj, const CxAllocator *a, int6
 void note_store_new_note_async(UiObject *obj, Note *note, execresult_func resultcb, void *userdata);
 void note_store_save_note_async(UiObject *obj, Note *note, execresult_func resultcb, void *userdata);
 
+void note_store_delete_async(UiObject *obj, Note *note, UiBool move_to_trash, execresult_func resultcb, void *userdata);
+
 #ifdef __cplusplus
 }
 #endif
index 779a6cc3d9432d1bebbe4abcac93fd395a75b955..a1da5c9d2cddac812176fbf284b460ea10b88ff7 100644 (file)
@@ -32,6 +32,7 @@
 #include "notebook.h"
 #include "editor.h"
 #include "note.h"
+#include "menu.h"
 
 #include <cx/array_list.h>
 #include <cx/hash_map.h>
@@ -60,7 +61,8 @@ void window_create() {
         UiModel* model = ui_model(obj->ctx, UI_STRING, "Name", UI_STRING_FREE, "Last Modified", -1);
         model->columnsize[0] = -1;
         model->getvalue = window_notelist_getvalue;
-        ui_table(obj, .model = model, .varname = "notes", .multiselection = TRUE, .onselection = action_note_selected, .onactivate = action_note_activated);
+        
+        ui_table(obj, .model = model, .varname = "notes", .contextmenu = get_notelist_context_menu(), .multiselection = TRUE, .onselection = action_note_selected, .onactivate = action_note_activated);
         
         // splitpane right: content
         ui_tabview_w(obj, wdata->document_tabview, .tabview = UI_TABVIEW_INVISIBLE, .varname = "note_type") {