[niepce] workspace: added delete folder command



commit 20910be51b670a812b26e0d5b7a88f358c65473d
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Nov 17 12:50:12 2017 -0500

    workspace: added delete folder command
    
    - NotificationType enum no longer have hard coded values
    - Added delete folder library client interface
    - Added create folder async version
    - Added FOLDER_DELETED notifiation type and associated enums and API
    - Added ui::confirm_dialog

 src/Makefile.am                       |    1 +
 src/engine/db/library.rs              |   11 +++++++
 src/engine/library/commands.rs        |    8 +++++
 src/engine/library/notification.rs    |   38 +++++++++++++----------
 src/libraryclient/clientimpl.rs       |   12 +++++++
 src/libraryclient/clientinterface.rs  |    2 +
 src/libraryclient/libraryclient.rs    |   14 +++++++++
 src/niepce/ui/dialogs/confirm.rs      |   48 +++++++++++++++++++++++++++++
 src/niepce/ui/dialogs/mod.rs          |   20 ++++++++++++-
 src/niepce/ui/workspacecontroller.cpp |   53 +++++++++++++++++++++++++++++++++
 src/niepce/ui/workspacecontroller.hpp |    5 +++
 src/rust_bindings.hpp                 |    1 +
 12 files changed, 195 insertions(+), 18 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 97156c8..bf29b29 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -42,6 +42,7 @@ RUST_SOURCES = \
        @top_srcdir@/src/niepce/mod.rs \
        @top_srcdir@/src/niepce/ui/mod.rs \
        @top_srcdir@/src/niepce/ui/dialogs/mod.rs \
+       @top_srcdir@/src/niepce/ui/dialogs/confirm.rs \
        @top_srcdir@/src/niepce/ui/dialogs/requestnewfolder.rs \
        $(NULL)
 
diff --git a/src/engine/db/library.rs b/src/engine/db/library.rs
index 5a6e768..852502f 100644
--- a/src/engine/db/library.rs
+++ b/src/engine/db/library.rs
@@ -274,6 +274,17 @@ impl Library {
         return Some(lf);
     }
 
+    pub fn delete_folder(&self, id: LibraryId) -> bool {
+        if let Some(ref conn) = self.dbconn {
+            if let Some(c) = conn.execute("DELETE FROM folders WHERE id=:1", &[&id]).ok() {
+                if c == 1 {
+                    return true;
+                }
+            }
+        }
+        false
+    }
+
     pub fn get_folder(&self, folder: &str) -> Option<LibFolder> {
         let foldername = try_opt!(Self::leaf_name_for_pathname(folder));
         let conn = try_opt!(self.dbconn.as_ref());
diff --git a/src/engine/library/commands.rs b/src/engine/library/commands.rs
index 972febd..4e6201e 100644
--- a/src/engine/library/commands.rs
+++ b/src/engine/library/commands.rs
@@ -132,6 +132,14 @@ pub fn cmd_create_folder(lib: &Library, name: &String, path: Option<String>) ->
     0
 }
 
+pub fn cmd_delete_folder(lib: &Library, id: LibraryId) -> bool {
+    if lib.delete_folder(id) {
+        lib.notify(Box::new(LibNotification::FolderDeleted(id)));
+        return true;
+    }
+    false
+}
+
 pub fn cmd_request_metadata(lib: &Library, file_id: LibraryId) -> bool {
     if let Some(lm) = lib.get_metadata(file_id) {
         lib.notify(Box::new(LibNotification::MetadataQueried(lm)));
diff --git a/src/engine/library/notification.rs b/src/engine/library/notification.rs
index 098777a..bd71666 100644
--- a/src/engine/library/notification.rs
+++ b/src/engine/library/notification.rs
@@ -31,23 +31,24 @@ pub type Content = QueriedContent;
 #[repr(i32)]
 #[allow(non_camel_case_types)]
 pub enum NotificationType {
-    NONE = 0,
-    NEW_LIBRARY_CREATED = 1,
-    ADDED_FOLDER = 2,
-    ADDED_FILE = 3,
-    ADDED_FILES = 4,
-    ADDED_KEYWORD = 5,
-    ADDED_LABEL = 6,
-    FOLDER_CONTENT_QUERIED = 7,
-    KEYWORD_CONTENT_QUERIED = 8,
-    METADATA_QUERIED = 9,
-    METADATA_CHANGED = 10,
-    LABEL_CHANGED = 11,
-    LABEL_DELETED = 12,
-    XMP_NEEDS_UPDATE = 13,
-    FOLDER_COUNTED = 14,
-    FOLDER_COUNT_CHANGE = 15,
-    FILE_MOVED = 16,
+    NONE,
+    NEW_LIBRARY_CREATED,
+    ADDED_FOLDER,
+    ADDED_FILE,
+    ADDED_FILES,
+    ADDED_KEYWORD,
+    ADDED_LABEL,
+    FOLDER_CONTENT_QUERIED,
+    FOLDER_DELETED,
+    KEYWORD_CONTENT_QUERIED,
+    METADATA_QUERIED,
+    METADATA_CHANGED,
+    LABEL_CHANGED,
+    LABEL_DELETED,
+    XMP_NEEDS_UPDATE,
+    FOLDER_COUNTED,
+    FOLDER_COUNT_CHANGE ,
+    FILE_MOVED,
 }
 
 #[repr(C)]
@@ -93,6 +94,7 @@ pub enum Notification {
     FolderContentQueried(Content),
     FolderCounted(FolderCount),
     FolderCountChanged(FolderCount),
+    FolderDeleted(LibraryId),
     KeywordContentQueried(Content),
     LabelChanged(Label),
     LabelDeleted(LibraryId),
@@ -146,6 +148,7 @@ pub extern "C" fn engine_library_notification_type(n: *const Notification) -> No
         Some(&Notification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
         Some(&Notification::FolderCounted(_)) => NotificationType::FOLDER_COUNTED,
         Some(&Notification::FolderCountChanged(_)) => NotificationType::FOLDER_COUNT_CHANGE,
+        Some(&Notification::FolderDeleted(_)) => NotificationType::FOLDER_DELETED,
         Some(&Notification::KeywordContentQueried(_)) =>
             NotificationType::KEYWORD_CONTENT_QUERIED,
         Some(&Notification::LabelChanged(_)) => NotificationType::LABEL_CHANGED,
@@ -164,6 +167,7 @@ pub extern "C" fn engine_library_notification_type(n: *const Notification) -> No
 pub extern "C" fn engine_library_notification_get_id(n: *const Notification) -> LibraryId {
     match unsafe { n.as_ref() } {
         Some(&Notification::MetadataChanged(ref changed)) => changed.id,
+        Some(&Notification::FolderDeleted(id)) => id,
         Some(&Notification::LabelDeleted(id)) => id,
         _ => unreachable!(),
     }
diff --git a/src/libraryclient/clientimpl.rs b/src/libraryclient/clientimpl.rs
index 65d1ec4..27a6b16 100644
--- a/src/libraryclient/clientimpl.rs
+++ b/src/libraryclient/clientimpl.rs
@@ -140,6 +140,18 @@ impl ClientInterface for ClientImpl {
         });
     }
 
+    fn create_folder(&mut self, name: String, path: Option<String>) {
+        self.schedule_op(move |lib| {
+            commands::cmd_create_folder(&lib, &name, path.clone()) != 0
+        });
+    }
+
+    fn delete_folder(&mut self, id: LibraryId) {
+        self.schedule_op(move |lib| {
+            commands::cmd_delete_folder(&lib, id)
+        });
+    }
+
     fn request_metadata(&mut self, file_id: LibraryId) {
         self.schedule_op(move |lib| {
             commands::cmd_request_metadata(&lib, file_id)
diff --git a/src/libraryclient/clientinterface.rs b/src/libraryclient/clientinterface.rs
index e58e8c1..4206b8c 100644
--- a/src/libraryclient/clientinterface.rs
+++ b/src/libraryclient/clientinterface.rs
@@ -33,6 +33,8 @@ pub trait ClientInterface {
     fn get_all_folders(&mut self);
     fn query_folder_content(&mut self, id: LibraryId);
     fn count_folder(&mut self, id: LibraryId);
+    fn create_folder(&mut self, name: String, path: Option<String>);
+    fn delete_folder(&mut self, id: LibraryId);
 
     fn request_metadata(&mut self, id: LibraryId);
     /// set the metadata
diff --git a/src/libraryclient/libraryclient.rs b/src/libraryclient/libraryclient.rs
index 5de76e4..ae470f1 100644
--- a/src/libraryclient/libraryclient.rs
+++ b/src/libraryclient/libraryclient.rs
@@ -94,6 +94,14 @@ impl ClientInterface for LibraryClient {
         self.pimpl.count_folder(id);
     }
 
+    fn create_folder(&mut self, name: String, path: Option<String>) {
+        self.pimpl.create_folder(name, path);
+    }
+
+    fn delete_folder(&mut self, id: LibraryId) {
+        self.pimpl.delete_folder(id);
+    }
+
     fn request_metadata(&mut self, id: LibraryId) {
         self.pimpl.request_metadata(id);
     }
@@ -209,6 +217,12 @@ pub extern "C" fn libraryclient_create_folder_sync(client: &mut LibraryClientWra
 }
 
 #[no_mangle]
+pub extern "C" fn libraryclient_delete_folder(client: &mut LibraryClientWrapper,
+                                             id: LibraryId) {
+    client.unwrap_mut().delete_folder(id);
+}
+
+#[no_mangle]
 pub extern "C" fn libraryclient_count_folder(client: &mut LibraryClientWrapper,
                                              folder_id: LibraryId) {
     client.unwrap_mut().count_folder(folder_id)
diff --git a/src/niepce/ui/dialogs/confirm.rs b/src/niepce/ui/dialogs/confirm.rs
new file mode 100644
index 0000000..0908798
--- /dev/null
+++ b/src/niepce/ui/dialogs/confirm.rs
@@ -0,0 +1,48 @@
+/*
+ * niepce - niepce/ui/dialogs/confirm.rs
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+use libc::c_char;
+use std::ffi::CStr;
+
+use glib::translate::*;
+use gtk::prelude::*;
+use gtk;
+use gtk_sys;
+use gtk::{
+    MessageDialog,
+};
+
+#[no_mangle]
+pub extern "C" fn dialog_confirm(message: *const c_char,
+                                 parent: *mut gtk_sys::GtkWindow) -> bool {
+
+    let mut result: bool = false;
+    let msg = unsafe { CStr::from_ptr(message) }.to_string_lossy();
+    let parent = unsafe { gtk::Window::from_glib_none(parent) };
+    let dialog = MessageDialog::new(Some(&parent), gtk::DIALOG_MODAL,
+                                    gtk::MessageType::Question, gtk::ButtonsType::YesNo,
+                                    &*msg);
+
+    if dialog.run() == gtk::ResponseType::Yes.into() {
+        result = true;
+    }
+    dialog.destroy();
+
+    result
+}
diff --git a/src/niepce/ui/dialogs/mod.rs b/src/niepce/ui/dialogs/mod.rs
index 77354fe..4bb2738 100644
--- a/src/niepce/ui/dialogs/mod.rs
+++ b/src/niepce/ui/dialogs/mod.rs
@@ -1,3 +1,21 @@
+/*
+ * niepce - niepce/ui/dialogs/mod.rs
+ *
+ * Copyright (C) 2017 Hubert Figuière
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
 
-
+pub mod confirm;
 pub mod requestnewfolder;
diff --git a/src/niepce/ui/workspacecontroller.cpp b/src/niepce/ui/workspacecontroller.cpp
index b26009f..5fe484e 100644
--- a/src/niepce/ui/workspacecontroller.cpp
+++ b/src/niepce/ui/workspacecontroller.cpp
@@ -96,6 +96,17 @@ void WorkspaceController::action_new_folder()
     ui::dialog_request_new_folder(getLibraryClient()->client(), window.gobj());
 }
 
+void WorkspaceController::action_delete_folder()
+{
+    auto id = get_selected_folder_id();
+    if (id) {
+        auto& window = std::dynamic_pointer_cast<NiepceWindow>(m_parent.lock())->gtkWindow();
+        if (ui::dialog_confirm(_("Delete selected folder?"), window.gobj())) {
+            ffi::libraryclient_delete_folder(getLibraryClient()->client(), id);
+        }
+    }
+}
+
 void WorkspaceController::action_file_import()
 {
     int result;
@@ -154,6 +165,12 @@ void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
         this->add_folder_item(f);
         break;
     }
+    case eng::NotificationType::FOLDER_DELETED:
+    {
+        auto id = engine_library_notification_get_id(&ln);
+        remove_folder_item(id);
+        break;
+    }
     case eng::NotificationType::ADDED_KEYWORD:
     {
         auto k = engine_library_notification_get_keyword(&ln);
@@ -200,6 +217,20 @@ void WorkspaceController::on_count_notification(int)
     DBG_OUT("received NOTIFICATION_COUNT");
 }
 
+eng::library_id_t WorkspaceController::get_selected_folder_id()
+{
+    auto selection = m_librarytree.get_selection();
+    auto selected = selection->get_selected();
+    if (selected == m_librarytree.get_model()->children().end()) {
+        return 0;
+    }
+    int type = (*selected)[m_librarycolumns.m_type];
+    eng::library_id_t id = (*selected)[m_librarycolumns.m_id];
+    if (type != FOLDER_ITEM) {
+        return 0;
+    }
+    return id;
+}
 
 void WorkspaceController::on_libtree_selection()
 {
@@ -221,6 +252,9 @@ void WorkspaceController::on_libtree_selection()
     default:
         DBG_OUT("selected something not a folder");
     }
+
+    Glib::RefPtr<Gio::SimpleAction>::cast_dynamic(
+        m_action_group->lookup_action("DeleteFolder"))->set_enabled(type == FOLDER_ITEM);
 }
 
 void WorkspaceController::on_row_expanded_collapsed(const Gtk::TreeIter& iter,
@@ -275,6 +309,16 @@ void WorkspaceController::add_keyword_item(const eng::Keyword* k)
     }
 }
 
+void WorkspaceController::remove_folder_item(eng::library_id_t id)
+{
+    auto iter = m_folderidmap.find(id);
+    if (iter == m_folderidmap.end()) {
+        return;
+    }
+    m_treestore->erase(iter->second);
+    m_folderidmap.erase(iter);
+}
+
 void WorkspaceController::add_folder_item(const eng::LibFolder* f)
 {
     int icon_idx = ICON_ROLL;
@@ -368,6 +412,15 @@ Gtk::Widget * WorkspaceController::buildWidget()
                     sigc::mem_fun(*this,
                                   &WorkspaceController::action_new_folder),
                     section, _("New Folder..."), "workspace");
+    auto action = fwk::add_action(m_action_group, "DeleteFolder",
+                                  sigc::mem_fun(*this,
+                                                &WorkspaceController::action_delete_folder),
+                                  section, _("Delete Folder"), "workspace");
+    action->set_enabled(false);
+
+    section = Gio::Menu::create();
+    menu->append_section(section);
+
     fwk::add_action(m_action_group, "Import",
                     sigc::mem_fun(*this,
                                   &WorkspaceController::action_file_import),
diff --git a/src/niepce/ui/workspacecontroller.hpp b/src/niepce/ui/workspacecontroller.hpp
index aad58f4..4598503 100644
--- a/src/niepce/ui/workspacecontroller.hpp
+++ b/src/niepce/ui/workspacecontroller.hpp
@@ -84,9 +84,12 @@ public:
     
     virtual Gtk::Widget * buildWidget() override;
 private:
+    /** Return the selected folder id. 0 if not a folder or no selection*/
+    eng::library_id_t get_selected_folder_id();
 
     /** action to create a new folder */
     void action_new_folder();
+    void action_delete_folder();
     /** action to import images */
     void action_file_import();
 
@@ -102,6 +105,8 @@ private:
 
     /** add a folder item to the treeview */
     void add_folder_item(const eng::LibFolder* f);
+    /** Remove a folder from the treeview */
+    void remove_folder_item(eng::library_id_t id);
     /** add a keyword item to the treeview */
     void add_keyword_item(const eng::Keyword* k);
     /** add a tree item in the treeview
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index c6de18b..ac5bb66 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -69,6 +69,7 @@ typedef ffi::FolderVirtualType FolderVirtualType;
 
 namespace ui {
   using ffi::dialog_request_new_folder;
+  using ffi::dialog_confirm;
 }
 
 #endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]