]> uap-core.de Git - note.git/commitdiff
implement rename for text notes main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 1 Aug 2026 11:44:19 +0000 (13:44 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 1 Aug 2026 11:44:19 +0000 (13:44 +0200)
application/backend/src/backend.rs
application/backend/src/storage.rs
application/note/src/main.rs
application/note/src/note.rs
entity/src/collection.rs
ui-rs/src/ui/list.rs
ui-rs/src/ui/menu.rs
ui-rs/src/ui/text.rs
ui-rs/src/ui/toolbar.rs
ui/gtk/window.c

index 3e1c912200ea5b4ab16d8ac7a3771e66fcd55062..823b2f04b6168f5c6f07c2a50476e4c6c41117e6 100644 (file)
@@ -227,7 +227,6 @@ impl Backend {
                 repository_id: Set(repo.repository_id),
                 name: Set("Notebooks".to_string()),
                 parent: Set("".to_string()),
-                icon: Set("".to_string()),
                 kind: Set(CollectionType::Notebook),
 
                 ..Default::default()
@@ -250,7 +249,6 @@ impl Backend {
                 repository_id: Set(repo.repository_id),
                 name: Set("Notes".to_string()),
                 parent: Set("/Notebooks".to_string()),
-                icon: Set("".to_string()),
                 kind: Set(CollectionType::Notebook),
 
                 ..Default::default()
@@ -399,7 +397,6 @@ impl BackendHandle {
                 profile_id: Set(profile_id),
                 name: Set(name.to_string()),
                 parent: Set(parent_path),
-                icon: Set("".to_string()),
                 kind: Set(CollectionType::Notebook),
 
                 ..Default::default()
@@ -691,15 +688,15 @@ impl BackendHandle {
                     return;
                 }
             };
-            
+
             let mut update = Note::update_many();
             if let Some(nodename ) = &nodename {
-                update = update.col_expr(Column::Nodename, Expr::value(nodename.clone()));
+                update = update.col_expr(Column::Nodename, Expr::value(nodename.clone())).col_expr(Column::FixedTitle, Expr::value(true));
             }
             if let Some(title ) = &title {
                 update = update.col_expr(Column::Title, Expr::value(title));
             }
-            
+
             let result = update
                     .filter(Column::NoteId.eq(note_id))
                     .exec(&bhandle.backend.db).await;
index 7ce260a83154a5a2ead580ea12455b0a022efaae..681fe855ff0d18c31e48aa67e43df1b710d95f10 100644 (file)
@@ -151,9 +151,13 @@ pub async fn check_free_nodename(db: &DatabaseConnection, collection_id: i32, no
 
     let path = get_note_storage_path(db, note_id).await?;
     if let Some(path) = path {
-        let m = fs::metadata(Path::new(&path)).await;
-        if m.is_ok() {
-            return Ok(false) // file exists
+        let p = Path::new(&path);
+        if let Some(parent) = p.parent() {
+            let new_path = parent.join(nodename);
+            let m = fs::metadata(Path::new(new_path.as_path())).await;
+            if m.is_ok() {
+                return Ok(false) // file exists
+            }
         }
     }
 
index dfe91510ac6691bdb19bf534fb001b60e5f9679d..f18e7623dbc7b4511e8edad528065f742642d98d 100644 (file)
@@ -144,6 +144,7 @@ fn create_menubar(app: &AppContext<MainWindow>) {
         menu.item("New").action("new_note").create();
         menu.item("New Window").onclick(|_| new_app_window() ).create();
         menu.separator();
+        menu.item("Rename").action("note_rename").create();
         menu.item("Delete").action("note_delete").create();
         menu.item("Edit Title").action("note_edit_title").create();
     });
@@ -171,6 +172,7 @@ fn create_toolbar(app: &AppContext<MainWindow>) {
     app.toolbar_appmenu(|menu|{
         menu.item("New Window").onclick(|_| new_app_window() ).create();
         menu.separator();
+        menu.item("Rename").action("note_rename").create();
         menu.item("Delete").action("delete_note").create();
         menu.item("Edit Title").action("note_edit_title").create();
     });
index 305008b6f2920e8a3d5ceb662868d3105ed07ca6..07c3fbf5f617974c5798ff41487134fb98c2e36c 100644 (file)
@@ -34,7 +34,7 @@ use sea_orm::sea_query::prelude::Utc;
 use backend::backend::{BackendHandle, BroadcastMessage, NoteContentRet, NoteId, NoteTitleUpdate, SaveNoteResult};
 use backend::lockmanager::NoteLock;
 use entity::note::NoteType;
-use ui_rs::{action, doc_cast, ui_actions, UiModel};
+use ui_rs::{action, dialog, doc_cast, ui_actions, UiModel};
 use ui_rs::ui::*;
 use crate::AppStates;
 use crate::window::NoteTypeTabView;
@@ -438,6 +438,78 @@ impl Note {
         };
         doc.ctx.unset_state(AppStates::NoteShowExtModInfo as i32);
     }
+
+    #[action]
+    pub fn note_rename(&mut self, event: &mut ActionEvent) {
+        let Some(doc) = self.doc.get_doc() else {
+            return;
+        };
+        let Some(obj) = &event.obj else {
+            return;
+        };
+        let NoteId::Id(note_id) = self.id else {
+            return;
+        };
+
+        let nodename = match &self.nodename {
+            Some(name) => name.as_str(),
+            None => "",
+        };
+
+        let proxy = doc.doc_proxy();
+        let collection_id = self.collection_id;
+        let backend = self.backend.clone();
+
+        obj.dialog()
+            .title("Rename Note")
+            .content("File Name")
+            .input(true)
+            .input_value(nodename)
+            .button1_label("OK")
+            .closebutton_label("Cancel")
+            .result(move |event|{
+                if let EventType::String(new_name) = &event.event_type && event.intval == 1 {
+                    // Rename OK
+                    // check if the new nodename is available
+                    let new_nodename = new_name.clone();
+                    backend.check_nodename(collection_id, note_id, new_name.as_str(), move|result|{
+                        proxy.call_mainthread(move|doc, note| {
+                            match result {
+                                Ok(available) => {
+                                    if available {
+                                        let proxy = doc.doc_proxy();
+                                        note.backend.rename_note(1, Some(new_nodename.clone()), None, |result|{
+                                            proxy.call_mainthread(|_doc, note|{
+                                                match result {
+                                                    Ok(updated) => {
+                                                        if updated.rows_affected != 1 {
+                                                            eprintln!("rename_note: unexpected number of rows affected");
+                                                        } else {
+                                                            note.nodename = Some(new_nodename);
+                                                            note.fixed_title = true;
+                                                        }
+                                                    },
+                                                    Err(e) => {
+                                                        eprintln!("note update failed: {:?}", e);
+                                                    }
+                                                }
+                                            });
+                                        });
+                                    } else {
+                                        let msg = format!("File {} already exists", new_nodename);
+                                        dialog!(title = "Rename Note", content = msg.as_str(), button1_label = "OK");
+                                    }
+                                }
+                                Err(e) => {
+                                    eprintln!("check_nodename failed: {:?}", e);
+                                }
+                            }
+                        });
+                    });
+                }
+            })
+            .create();
+    }
 }
 
 impl NoteViewModel for Note {
index afffff612f1e445bf3d3c6a1f0f743be2a860265..f89817888f1337e5c11c1252c36b38c2ee6cb82f 100644 (file)
@@ -43,7 +43,7 @@ pub struct Model {
 
     pub name: String,
     pub parent: String,
-    pub icon: String,
+    pub icon: Option<String>,
     pub kind: CollectionType,
     pub storage: LocalStorageSetting
 }
index fc55a269107779b33b64a155918c74a88adaf2da..3bb7c6969b17818236eab44369c963a39ad53ce8 100644 (file)
@@ -338,7 +338,7 @@ impl<'a, T, E> ListViewBuilder<'a, T, E> {
 
     pub fn onactivate<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_list_args_set_onactivate(self.args, Some(event::event_wrapper::<T>));
@@ -357,7 +357,7 @@ impl<'a, T, E> ListViewBuilder<'a, T, E> {
 
     pub fn onselection<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_list_args_set_onselection(self.args, Some(event::event_wrapper::<T>));
@@ -575,7 +575,7 @@ impl<'a, T, E> TableViewBuilder<'a, T, E> {
 
     pub fn onactivate<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_list_args_set_onactivate(self.args, Some(event::event_wrapper::<T>));
@@ -595,7 +595,7 @@ impl<'a, T, E> TableViewBuilder<'a, T, E> {
 
     pub fn onselection<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_list_args_set_onselection(self.args, Some(event::event_wrapper::<T>));
@@ -791,7 +791,7 @@ impl<'a, T, E> SourceListBuilder<'a, T, E> {
 
     pub fn onactivate<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_sourcelist_args_set_onactivate(self.args, Some(event::event_wrapper::<T>));
@@ -802,7 +802,7 @@ impl<'a, T, E> SourceListBuilder<'a, T, E> {
 
     pub fn onbuttonclick<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_sourcelist_args_set_onbuttonclick(self.args, Some(event::event_wrapper::<T>));
index bf060ec2734d1c07342c163bb0fcac6f41f9d6ac..69e9fa6911a00961330827bb5a573d5546448396 100644 (file)
@@ -160,7 +160,7 @@ impl<T: UiModel + UiActions> MenuItemBuilder<T> {
 
     pub fn onclick<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ctx = UiContext { ptr: self.ctx };
         let ptr = ctx.reg_box(wrapper);
         unsafe {
@@ -211,7 +211,7 @@ impl<T: UiModel + UiActions> MenuToggleItemBuilder<T> {
 
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ctx = UiContext { ptr: self.ctx };
         let ptr = ctx.reg_box(wrapper);
         unsafe {
index cbbe19edf17966764b2e74d16001369ac76f8c2f..5eb92ab85dfc801eaf76c0fbad2f26bdfa64e9c1 100644 (file)
@@ -272,7 +272,7 @@ impl<'a, T> TextAreaBuilder<'a, T> {
 
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f) );
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textarea_args_set_onchange(self.args, Some(event::event_wrapper::<T>));
@@ -291,7 +291,7 @@ impl<'a, T> TextAreaBuilder<'a, T> {
 
     pub fn ontextchanged<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textarea_args_set_ontextchanged(self.args, Some(event::event_wrapper::<T>));
@@ -584,7 +584,7 @@ impl<'a, T> TextFieldBuilder<'a, T> {
 
     pub fn onactivate<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textfield_args_set_onactivate(self.args, Some(event::event_wrapper::<T>));
@@ -603,7 +603,7 @@ impl<'a, T> TextFieldBuilder<'a, T> {
 
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ptr = self.obj.ctx.reg_box(wrapper);
         unsafe {
             ui_textfield_args_set_onchange(self.args, Some(event::event_wrapper::<T>));
index 7cffe1d1659df93f233f990592a1eb313790ad84..54678cd5e049a32ad993ef5e1c643e3b810cad96 100644 (file)
@@ -190,7 +190,7 @@ impl<T: UiModel + UiActions> ToolbarItemBuilder<T> {
 
     pub fn onclick<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ctx = UiContext { ptr: self.ctx };
         let ptr = ctx.reg_box(wrapper);
         unsafe {
@@ -271,7 +271,7 @@ impl<T: UiModel + UiActions> ToolbarToggleItemBuilder<T> {
 
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ctx = UiContext { ptr: self.ctx };
         let ptr = ctx.reg_box(wrapper);
         unsafe {
@@ -368,7 +368,7 @@ impl<T: UiModel + UiActions> ToolbarContentToggleItemBuilder<T> {
 
     pub fn onchange<F>(&mut self, f: F) -> &mut Self
     where F: FnMut(&mut event::Event<T>) + 'static {
-        let wrapper = Box::new(EventWrapper { callback: Box::new(f) });
+        let wrapper = Box::new(EventWrapper::new(f));
         let ctx = UiContext { ptr: self.ctx };
         let ptr = ctx.reg_box(wrapper);
         unsafe {
index 009d432cac07cd802c7be67fa485ef4147ecb470..fc6e9e28318e8f70ed0150c95ae9fbe6521e6c21 100644 (file)
@@ -511,8 +511,8 @@ UIEXPORT void ui_splitview_window_set_visible(UiObject *obj, int pane, UiBool vi
 static void dialog_response(AdwAlertDialog *self, gchar *response, UiEventData *data) {
     UiEvent evt;
     evt.obj = data->obj;
-    evt.document = evt.obj->ctx->document;
-    evt.window = evt.obj->window;
+    evt.document = evt.obj ? evt.obj->ctx->document : NULL;
+    evt.window = evt.obj ? evt.obj->window : NULL;
     evt.eventdata = NULL;
     evt.eventdatatype = 0;
     evt.intval = 0;