[niepce/lr-import: 13/20] Issue #40 - Added support for albums in UI




commit 086e2a05906daa1417995450d3cfba8c7dff0a8d
Author: Hubert Figuière <hub figuiere net>
Date:   Fri Dec 10 21:51:06 2021 -0500

    Issue #40 - Added support for albums in UI
    
    - use symbolic icons
    - added necessary method to LibraryClient
    
    https://gitlab.gnome.org/GNOME/niepce/-/issues/40

 crates/npc-engine/src/db/album.rs                  | 14 ++++++
 crates/npc-engine/src/db/library.rs                | 27 +++++++++++
 crates/npc-engine/src/library/commands.rs          | 46 ++++++++++++++++++
 crates/npc-engine/src/library/notification.rs      | 23 ++++++++-
 crates/npc-engine/src/libraryclient.rs             | 31 ++++++++++++
 .../src/libraryclient/clientinterface.rs           |  4 ++
 data/icons/library-artists-symbolic.svg            |  2 +
 src/niepce/gresource.xml                           |  2 +-
 src/niepce/ui/workspacecontroller.cpp              | 56 +++++++++++++++++++---
 src/niepce/ui/workspacecontroller.hpp              | 43 +++++++++--------
 src/rust_bindings.hpp                              |  1 +
 11 files changed, 220 insertions(+), 29 deletions(-)
---
diff --git a/crates/npc-engine/src/db/album.rs b/crates/npc-engine/src/db/album.rs
index 58f62ea..a9473fc 100644
--- a/crates/npc-engine/src/db/album.rs
+++ b/crates/npc-engine/src/db/album.rs
@@ -17,6 +17,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+use libc::c_char;
+use std::ffi::CString;
+
 use super::FromDb;
 use super::LibraryId;
 use super::SortOrder;
@@ -89,3 +92,14 @@ impl FromDb for Album {
         Ok(Album::new(row.get(0)?, &name, row.get(2)?))
     }
 }
+
+#[no_mangle]
+pub extern "C" fn engine_db_album_id(obj: &Album) -> i64 {
+    obj.id() as i64
+}
+
+#[no_mangle]
+pub extern "C" fn engine_db_album_name(obj: &Album) -> *mut c_char {
+    let cstr = CString::new(obj.name()).unwrap();
+    cstr.into_raw()
+}
diff --git a/crates/npc-engine/src/db/library.rs b/crates/npc-engine/src/db/library.rs
index afedf7d..0f300db 100644
--- a/crates/npc-engine/src/db/library.rs
+++ b/crates/npc-engine/src/db/library.rs
@@ -664,6 +664,31 @@ impl Library {
         Err(Error::NoSqlDb)
     }
 
+    pub fn count_album(&self, id: LibraryId) -> Result<i64> {
+        if let Some(ref conn) = self.dbconn {
+            let mut stmt = conn.prepare(
+                "SELECT COUNT(album_id) FROM albuming \
+                 WHERE album_id=?1;",
+            )?;
+            let mut rows = stmt.query(params![id])?;
+            return match rows.next() {
+                Ok(Some(row)) => Ok(row.get(0)?),
+                Err(err) => Err(Error::from(err)),
+                Ok(None) => Err(Error::NotFound),
+            };
+        }
+        Err(Error::NoSqlDb)
+    }
+
+    pub fn get_album_content(&self, album_id: LibraryId) -> Result<Vec<LibFile>> {
+        self.get_content(
+            album_id,
+            "files.id IN \
+             (SELECT file_id FROM albuming \
+             WHERE album_id=?1) ",
+        )
+    }
+
     /// Add an image to an album.
     pub fn add_to_album(&self, image_id: LibraryId, album_id: LibraryId) -> Result<()> {
         if let Some(ref conn) = self.dbconn {
@@ -954,6 +979,8 @@ impl Library {
     }
 
     /// Set properties for an image.
+    ///
+    /// XXX only the XMP Packet is currently supported.
     pub fn set_image_properties(
         &self,
         image_id: LibraryId,
diff --git a/crates/npc-engine/src/library/commands.rs b/crates/npc-engine/src/library/commands.rs
index a60999a..f5f0bf2 100644
--- a/crates/npc-engine/src/library/commands.rs
+++ b/crates/npc-engine/src/library/commands.rs
@@ -198,6 +198,26 @@ pub fn cmd_list_all_albums(lib: &Library) -> bool {
     }
 }
 
+pub fn cmd_count_album(lib: &Library, id: LibraryId) -> bool {
+    match lib.count_album(id) {
+        Ok(count) => {
+            // This time it's a fatal error since the purpose of this comand
+            // is to retrieve.
+            match lib.notify(LibNotification::AlbumCounted(Count { id, count })) {
+                Err(err) => {
+                    err_out!("Failed to notify AlbumCounted {:?}", err);
+                    false
+                }
+                Ok(_) => true,
+            }
+        }
+        Err(err) => {
+            err_out_line!("count_album failed: {:?}", err);
+            false
+        }
+    }
+}
+
 pub fn cmd_create_album(lib: &Library, name: &str, parent: LibraryId) -> LibraryId {
     match lib.add_album(name, parent) {
         Ok(album) => {
@@ -238,6 +258,32 @@ pub fn cmd_add_to_album(lib: &Library, image_id: LibraryId, album_id: LibraryId)
     }
 }
 
+pub fn cmd_query_album_content(lib: &Library, album_id: LibraryId) -> bool {
+    match lib.get_album_content(album_id) {
+        Ok(fl) => {
+            let mut content = QueriedContent::new(album_id);
+            for f in fl {
+                content.push(f);
+            }
+            let value = LibNotification::AlbumContentQueried(content);
+
+            // This time it's a fatal error since the purpose of this comand
+            // is to retrieve.
+            match lib.notify(value) {
+                Err(err) => {
+                    err_out!("Failed to notify AlbumContent {:?}", err);
+                    false
+                }
+                Ok(_) => true,
+            }
+        }
+        Err(err) => {
+            err_out_line!("Get album content failed {:?}", err);
+            false
+        }
+    }
+}
+
 pub fn cmd_request_metadata(lib: &Library, file_id: LibraryId) -> bool {
     match lib.get_metadata(file_id) {
         Ok(lm) => {
diff --git a/crates/npc-engine/src/library/notification.rs b/crates/npc-engine/src/library/notification.rs
index 9747ce2..2af98ae 100644
--- a/crates/npc-engine/src/library/notification.rs
+++ b/crates/npc-engine/src/library/notification.rs
@@ -40,6 +40,9 @@ pub enum NotificationType {
     ADDED_LABEL,
     ADDED_ALBUM,
     ADDED_TO_ALBUM,
+    ALBUM_CONTENT_QUERIED,
+    ALBUM_COUNTED,
+    ALBUM_COUNT_CHANGE,
     FOLDER_CONTENT_QUERIED,
     FOLDER_DELETED,
     FOLDER_COUNTED,
@@ -125,6 +128,9 @@ pub enum LibNotification {
     AddedLabel(Label),
     AddedAlbum(Album),
     AddedToAlbum((LibraryId, LibraryId)),
+    AlbumContentQueried(QueriedContent),
+    AlbumCounted(Count),
+    AlbumCountChanged(Count),
     FileMoved(FileMove),
     FileStatusChanged(FileStatusChange),
     FolderContentQueried(QueriedContent),
@@ -181,6 +187,9 @@ pub unsafe extern "C" fn engine_library_notification_type(
         Some(&LibNotification::AddedLabel(_)) => NotificationType::ADDED_LABEL,
         Some(&LibNotification::AddedAlbum(_)) => NotificationType::ADDED_ALBUM,
         Some(&LibNotification::AddedToAlbum(_)) => NotificationType::ADDED_TO_ALBUM,
+        Some(&LibNotification::AlbumCounted(_)) => NotificationType::ALBUM_COUNTED,
+        Some(&LibNotification::AlbumCountChanged(_)) => NotificationType::ALBUM_COUNT_CHANGE,
+        Some(&LibNotification::AlbumContentQueried(_)) => NotificationType::ALBUM_CONTENT_QUERIED,
         Some(&LibNotification::FileMoved(_)) => NotificationType::FILE_MOVED,
         Some(&LibNotification::FileStatusChanged(_)) => NotificationType::FILE_STATUS_CHANGED,
         Some(&LibNotification::FolderContentQueried(_)) => NotificationType::FOLDER_CONTENT_QUERIED,
@@ -244,7 +253,9 @@ pub unsafe extern "C" fn engine_library_notification_get_count(
     n: *const LibNotification,
 ) -> *const Count {
     match n.as_ref() {
-        Some(&LibNotification::FolderCountChanged(ref c))
+        Some(&LibNotification::AlbumCountChanged(ref c))
+        | Some(&LibNotification::AlbumCounted(ref c))
+        | Some(&LibNotification::FolderCountChanged(ref c))
         | Some(&LibNotification::FolderCounted(ref c))
         | Some(&LibNotification::KeywordCountChanged(ref c))
         | Some(&LibNotification::KeywordCounted(ref c)) => c,
@@ -271,3 +282,13 @@ pub unsafe extern "C" fn engine_library_notification_get_keyword(
         _ => unreachable!(),
     }
 }
+
+#[no_mangle]
+pub unsafe extern "C" fn engine_library_notification_get_album(
+    n: *const LibNotification,
+) -> *const Album {
+    match n.as_ref() {
+        Some(&LibNotification::AddedAlbum(ref a)) => a,
+        _ => unreachable!(),
+    }
+}
diff --git a/crates/npc-engine/src/libraryclient.rs b/crates/npc-engine/src/libraryclient.rs
index 36c262c..de4d1c8 100644
--- a/crates/npc-engine/src/libraryclient.rs
+++ b/crates/npc-engine/src/libraryclient.rs
@@ -194,6 +194,11 @@ impl ClientInterface for LibraryClient {
         self.schedule_op(move |lib| commands::cmd_list_all_albums(&lib));
     }
 
+    /// Count album
+    fn count_album(&mut self, album_id: LibraryId) {
+        self.schedule_op(move |lib| commands::cmd_count_album(&lib, album_id));
+    }
+
     /// Create an album (async)
     fn create_album(&mut self, name: String, parent: LibraryId) {
         self.schedule_op(move |lib| commands::cmd_create_album(&lib, &name, parent) != 0);
@@ -204,6 +209,11 @@ impl ClientInterface for LibraryClient {
         self.schedule_op(move |lib| commands::cmd_add_to_album(&lib, image_id, album_id));
     }
 
+    /// Query content for album.
+    fn query_album_content(&mut self, album_id: LibraryId) {
+        self.schedule_op(move |lib| commands::cmd_query_album_content(&lib, album_id));
+    }
+
     fn request_metadata(&mut self, file_id: LibraryId) {
         self.schedule_op(move |lib| commands::cmd_request_metadata(&lib, file_id));
     }
@@ -382,6 +392,11 @@ pub extern "C" fn libraryclient_get_all_folders(client: &mut LibraryClientWrappe
     client.unwrap_mut().get_all_folders();
 }
 
+#[no_mangle]
+pub extern "C" fn libraryclient_get_all_albums(client: &mut LibraryClientWrapper) {
+    client.unwrap_mut().get_all_albums();
+}
+
 #[no_mangle]
 pub extern "C" fn libraryclient_query_folder_content(
     client: &mut LibraryClientWrapper,
@@ -431,6 +446,22 @@ pub extern "C" fn libraryclient_count_keyword(client: &mut LibraryClientWrapper,
     client.unwrap_mut().count_keyword(id);
 }
 
+#[no_mangle]
+pub extern "C" fn libraryclient_count_album(
+    client: &mut LibraryClientWrapper,
+    album_id: LibraryId,
+) {
+    client.unwrap_mut().count_album(album_id);
+}
+
+#[no_mangle]
+pub extern "C" fn libraryclient_query_album_content(
+    client: &mut LibraryClientWrapper,
+    album_id: LibraryId,
+) {
+    client.unwrap_mut().query_album_content(album_id);
+}
+
 #[no_mangle]
 pub extern "C" fn libraryclient_request_metadata(
     client: &mut LibraryClientWrapper,
diff --git a/crates/npc-engine/src/libraryclient/clientinterface.rs 
b/crates/npc-engine/src/libraryclient/clientinterface.rs
index ab666d8..6688b70 100644
--- a/crates/npc-engine/src/libraryclient/clientinterface.rs
+++ b/crates/npc-engine/src/libraryclient/clientinterface.rs
@@ -42,10 +42,14 @@ pub trait ClientInterface {
 
     /// get all the albums
     fn get_all_albums(&mut self);
+    /// Count album content.
+    fn count_album(&mut self, album_id: LibraryId);
     /// Create an album (async)
     fn create_album(&mut self, name: String, parent: LibraryId);
     /// Add an image to an album.
     fn add_to_album(&mut self, image_id: LibraryId, album_id: LibraryId);
+    /// Query content for album.
+    fn query_album_content(&mut self, album_id: LibraryId);
 
     fn request_metadata(&mut self, id: LibraryId);
     /// set the metadata
diff --git a/data/icons/library-artists-symbolic.svg b/data/icons/library-artists-symbolic.svg
new file mode 100644
index 0000000..dd59798
--- /dev/null
+++ b/data/icons/library-artists-symbolic.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink"; height="16px" viewBox="0 
0 16 16" width="16px"><filter id="a" height="100%" width="100%" x="0%" y="0%"><feColorMatrix 
in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/></filter><mask id="b"><g 
filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/></g></mask><clipPath id="c"><path d="m 
0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="d"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" 
fill-opacity="0.05"/></g></mask><clipPath id="e"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask 
id="f"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath 
id="g"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="h"><g filter="url(#a)"><path d="m 0 0 h 
16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="i"><path d="m 0 0 h 1600 v 1200 h -1600 
z"/></clipPath><mask id="j"><g filter="url(#a)">
 <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath id="k"><path d="m 0 0 h 1600 v 
1200 h -1600 z"/></clipPath><mask id="l"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" 
fill-opacity="0.05"/></g></mask><clipPath id="m"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask 
id="n"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/></g></mask><clipPath 
id="o"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><mask id="p"><g filter="url(#a)"><path d="m 0 0 h 
16 v 16 h -16 z" fill-opacity="0.3"/></g></mask><clipPath id="q"><path d="m 0 0 h 1600 v 1200 h -1600 
z"/></clipPath><mask id="r"><g filter="url(#a)"><path d="m 0 0 h 16 v 16 h -16 z" 
fill-opacity="0.5"/></g></mask><clipPath id="s"><path d="m 0 0 h 1600 v 1200 h -1600 z"/></clipPath><g 
clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -580 -844)"><path d="m 562.460938 212.058594 h 
10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill=
 "#2e3436"/></g><path d="m 5 0 c -1.089844 0 -2 0.910156 -2 2 v 9 c 0 1.089844 0.910156 2 2 2 h 9 c 1.089844 
0 2 -0.910156 2 -2 v -9 c 0 -1.089844 -0.910156 -2 -2 -2 z m 4.5 2 c 1.105469 0 2 0.894531 2 2 s -0.894531 2 
-2 2 s -2 -0.894531 -2 -2 s 0.894531 -2 2 -2 z m -0.5 5 h 1 c 1.660156 0 3 1.339844 3 3 v 0.332031 c 0 
0.667969 -0.667969 0.667969 -0.667969 0.667969 h -5.664062 s -0.667969 0 -0.667969 -0.667969 v -0.332031 c 0 
-1.660156 1.339844 -3 3 -3 z m 0 0" fill="#2e3436"/><path d="m 2 3 c -1.089844 0 -2 0.910156 -2 2 v 9 c 0 
1.089844 0.910156 2 2 2 h 9 c 1.089844 0 2 -0.910156 2 -2 h -11 z m 0 0" fill="#2e3436"/><g 
clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -580 -844)"><path d="m 16 748 h 1 v 1 h -1 z m 0 
0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 
-580 -844)"><path d="m 17 747 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g 
clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0
  1 -580 -844)"><path d="m 18 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g 
clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -580 -844)"><path d="m 16 750 h 1 v 1 h -1 z m 0 
0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 
-580 -844)"><path d="m 17 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/></g><g 
clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -580 -844)"><path d="m 19 751 h 1 v 1 h -1 z m 0 
0" fill="#2e3436" fill-rule="evenodd"/></g><g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 
-580 -844)"><path d="m 136 776 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/></g><g clip-path="url(#s)" 
mask="url(#r)" transform="matrix(1 0 0 1 -580 -844)"><path d="m 219 758 h 3 v 12 h -3 z m 0 0" 
fill="#2e3436"/></g></svg>
diff --git a/src/niepce/gresource.xml b/src/niepce/gresource.xml
index 86820a9..d2c09dc 100644
--- a/src/niepce/gresource.xml
+++ b/src/niepce/gresource.xml
@@ -18,7 +18,7 @@
     <file alias="/pixmaps/niepce-unknown-fmt.png">data/icons/niepce-unknown-fmt.png</file>
     <file alias="/pixmaps/niepce-image-generic.png">data/icons/niepce-image-generic.png</file>
     <file alias="/pixmaps/niepce-image-missing.png">data/icons/niepce-image-missing.png</file>
-
+    <file alias="/icons/library-artists-symbolic.svg">data/icons/library-artists-symbolic.svg</file>
     <file alias="/ui/editlabels.ui">src/niepce/ui/dialogs/editlabels.ui</file>
     <file alias="/ui/importdialog.ui">src/niepce/ui/dialogs/importdialog.ui</file>
     <file alias="/ui/importlibrary.ui">src/niepce/ui/dialogs/importlibrary.ui</file>
diff --git a/src/niepce/ui/workspacecontroller.cpp b/src/niepce/ui/workspacecontroller.cpp
index 2bf52ee..73d1f6f 100644
--- a/src/niepce/ui/workspacecontroller.cpp
+++ b/src/niepce/ui/workspacecontroller.cpp
@@ -1,7 +1,7 @@
 /*
  * niepce - ui/workspacecontroller.cpp
  *
- * Copyright (C) 2007-2020 Hubert Figuière
+ * Copyright (C) 2007-2021 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
@@ -54,11 +54,12 @@ WorkspaceController::WorkspaceController(const Glib::RefPtr<Gio::SimpleActionGro
         int icon_id;
         const char *icon_name;
     } icons[] = {
-        { ICON_FOLDER, "folder" },
+        { ICON_FOLDER, "folder-symbolic" },
         { ICON_PROJECT, "applications-accessories" },
-        { ICON_ROLL, "emblem-photos" },
-        { ICON_TRASH, "user-trash" },
-        { ICON_KEYWORD, "application-certificate" },
+        { ICON_ROLL, "emblem-photos-symbolic" },
+        { ICON_TRASH, "user-trash-symbolic" },
+        { ICON_KEYWORD, "application-certificate-symbolic" },
+        { ICON_ALBUM, "library-artists-symbolic" },
         { 0, nullptr }
     };
 
@@ -181,8 +182,15 @@ void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
         add_keyword_item(k);
         break;
     }
+    case eng::NotificationType::ADDED_ALBUM:
+    {
+        auto a = engine_library_notification_get_album(&ln);
+        this->add_album_item(a);
+        break;
+    }
     case eng::NotificationType::FOLDER_COUNTED:
     case eng::NotificationType::KEYWORD_COUNTED:
+    case eng::NotificationType::ALBUM_COUNTED:
     {
         auto count = engine_library_notification_get_count(&ln);
         DBG_OUT("count for container %Ld is %Ld", (long long)count->id, (long long)count->count);
@@ -194,6 +202,9 @@ void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
         case eng::NotificationType::KEYWORD_COUNTED:
             iter = m_keywordsidmap.find(count->id);
             break;
+        case eng::NotificationType::ALBUM_COUNTED:
+            iter = m_albumsidmap.find(count->id);
+            break;
         default:
             DBG_ASSERT(false, "should never happen");
             break;
@@ -208,6 +219,7 @@ void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
     }
     case eng::NotificationType::FOLDER_COUNT_CHANGE:
     case eng::NotificationType::KEYWORD_COUNT_CHANGE:
+    case eng::NotificationType::ALBUM_COUNT_CHANGE:
     {
         auto count = engine_library_notification_get_count(&ln);
         DBG_OUT("count change for container %Ld is %Ld", (long long)count->id,
@@ -220,6 +232,9 @@ void WorkspaceController::on_lib_notification(const eng::LibNotification &ln)
         case eng::NotificationType::KEYWORD_COUNT_CHANGE:
             iter = m_keywordsidmap.find(count->id);
             break;
+        case eng::NotificationType::ALBUM_COUNT_CHANGE:
+            iter = m_albumsidmap.find(count->id);
+            break;
         default:
             DBG_ASSERT(false, "should never happen");
             break;
@@ -279,6 +294,10 @@ void WorkspaceController::on_libtree_selection()
         ffi::libraryclient_query_keyword_content(getLibraryClient()->client(), id);
         break;
 
+    case ALBUM_ITEM:
+        ffi::libraryclient_query_album_content(getLibraryClient()->client(), id);
+        break;
+
     default:
         DBG_OUT("selected something not a folder");
     }
@@ -302,6 +321,9 @@ void WorkspaceController::on_row_expanded_collapsed(const Gtk::TreeIter& iter,
     case PROJECTS_ITEM:
         key = "workspace_projects_expanded";
         break;
+    case ALBUMS_ITEM:
+        key = "workspace_albums_expanded";
+        break;
     case KEYWORDS_ITEM:
         key = "workspace_keywords_expanded";
         break;
@@ -391,6 +413,21 @@ WorkspaceController::add_item(const Glib::RefPtr<Gtk::TreeStore> &treestore,
     return iter;
 }
 
+void WorkspaceController::add_album_item(const eng::Album* a)
+{
+    auto children = m_albumsNode->children();
+    bool was_empty = children.empty();
+    auto album = fwk::RustFfiString(engine_db_album_name(a));
+    auto iter = add_item(m_treestore, children,
+                         m_icons[ICON_ALBUM], album.c_str(),
+                         engine_db_album_id(a), ALBUM_ITEM);
+    ffi::libraryclient_count_album(getLibraryClient()->client(), engine_db_album_id(a));
+    m_albumsidmap[engine_db_album_id(a)] = iter;
+    if (was_empty) {
+        expand_from_cfg("workspace_albums_expanded", m_albumsNode);
+    }
+}
+
 Gtk::Widget * WorkspaceController::buildWidget()
 {
     if(m_widget) {
@@ -404,13 +441,17 @@ Gtk::Widget * WorkspaceController::buildWidget()
         "Model isn't persistent");
 
     m_folderNode = add_item(m_treestore, m_treestore->children(),
-                            m_icons[ICON_FOLDER], 
+                            m_icons[ICON_FOLDER],
                             Glib::ustring(_("Pictures")), 0,
                             FOLDERS_ITEM);
     m_projectNode = add_item(m_treestore, m_treestore->children(),
-                             m_icons[ICON_PROJECT], 
+                             m_icons[ICON_PROJECT],
                              Glib::ustring(_("Projects")), 0,
                              PROJECTS_ITEM);
+    m_albumsNode = add_item(m_treestore, m_treestore->children(),
+                            m_icons[ICON_ALBUM],
+                            Glib::ustring(_("Albums")), 0,
+                            ALBUMS_ITEM);
     m_keywordsNode = add_item(m_treestore, m_treestore->children(),
                               m_icons[ICON_KEYWORD],
                               Glib::ustring(_("Keywords")), 0,
@@ -511,6 +552,7 @@ void WorkspaceController::on_ready()
     if (libraryClient) {
         ffi::libraryclient_get_all_folders(libraryClient->client());
         ffi::libraryclient_get_all_keywords(libraryClient->client());
+        ffi::libraryclient_get_all_albums(libraryClient->client());
     }
 }
 
diff --git a/src/niepce/ui/workspacecontroller.hpp b/src/niepce/ui/workspacecontroller.hpp
index af91626..627c137 100644
--- a/src/niepce/ui/workspacecontroller.hpp
+++ b/src/niepce/ui/workspacecontroller.hpp
@@ -1,7 +1,7 @@
 /*
- * niepce - ui/workspacecontroller.h
+ * niepce - ui/workspacecontroller.hpp
  *
- * Copyright (C) 2007-2020 Hubert Figuière
+ * Copyright (C) 2007-2021 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
@@ -31,10 +31,6 @@
 #include "fwk/toolkit/notification.hpp"
 #include "niepce/ui/niepcewindow.hpp"
 
-namespace Gtk {
-}
-
-
 namespace ui {
 
 class WorkspaceController
@@ -44,9 +40,11 @@ public:
     typedef std::shared_ptr<WorkspaceController> Ptr;
 
     enum {
+        ALBUMS_ITEM,
         FOLDERS_ITEM,
         PROJECTS_ITEM,
         KEYWORDS_ITEM,
+        ALBUM_ITEM,
         FOLDER_ITEM,
         PROJECT_ITEM,
         KEYWORD_ITEM
@@ -113,6 +111,8 @@ private:
     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 an album item to the treeview */
+    void add_album_item(const eng::Album* a);
     /** add a tree item in the treeview
      * @param treestore the treestore to add to
      * @param childrens the children subtree to add to
@@ -121,10 +121,10 @@ private:
      * @param id the item id (in the database)
      * @paran type the type of node
      */
-    Gtk::TreeModel::iterator add_item(const Glib::RefPtr<Gtk::TreeStore> & treestore, 
+    Gtk::TreeModel::iterator add_item(const Glib::RefPtr<Gtk::TreeStore>& treestore,
                                       const Gtk::TreeNodeChildren & childrens,
                                       const Glib::RefPtr<Gdk::Pixbuf> & icon,
-                                      const Glib::ustring & label, 
+                                      const Glib::ustring& label,
                                       eng::library_id_t id, int type) const;
 
     void expand_from_cfg(const char* key, const Gtk::TreeIter& treenode);
@@ -135,24 +135,27 @@ private:
         ICON_ROLL,
         ICON_TRASH,
         ICON_KEYWORD,
+        ICON_ALBUM,
         _ICON_SIZE
     };
 
     Glib::RefPtr<Gio::SimpleActionGroup> m_action_group;
 
-    std::array< Glib::RefPtr<Gdk::Pixbuf>, _ICON_SIZE > m_icons;
-    WorkspaceTreeColumns           m_librarycolumns;
-    Gtk::Box                       m_vbox;
-    Gtk::Label                     m_label;
-    Gtk::TreeView                  m_librarytree;
+    std::array<Glib::RefPtr<Gdk::Pixbuf>, _ICON_SIZE> m_icons;
+    WorkspaceTreeColumns m_librarycolumns;
+    Gtk::Box m_vbox;
+    Gtk::Label m_label;
+    Gtk::TreeView m_librarytree;
     Gtk::Menu* m_context_menu;
-    Gtk::TreeModel::iterator       m_folderNode;  /**< the folder node */
-    Gtk::TreeModel::iterator       m_projectNode; /**< the project node */
-    Gtk::TreeModel::iterator       m_keywordsNode; /**< the keywords node */
-    Glib::RefPtr<Gtk::TreeStore>   m_treestore;   /**< the treestore */
-    std::map<eng::library_id_t, Gtk::TreeIter>   m_folderidmap;
-    std::map<eng::library_id_t, Gtk::TreeIter>   m_projectidmap;
-    std::map<eng::library_id_t, Gtk::TreeIter>   m_keywordsidmap;
+    Gtk::TreeModel::iterator m_folderNode;  /**< the folder node */
+    Gtk::TreeModel::iterator m_projectNode; /**< the project node */
+    Gtk::TreeModel::iterator m_albumsNode; /**< the albums node */
+    Gtk::TreeModel::iterator m_keywordsNode; /**< the keywords node */
+    Glib::RefPtr<Gtk::TreeStore> m_treestore;   /**< the treestore */
+    std::map<eng::library_id_t, Gtk::TreeIter> m_folderidmap;
+    std::map<eng::library_id_t, Gtk::TreeIter> m_projectidmap;
+    std::map<eng::library_id_t, Gtk::TreeIter> m_keywordsidmap;
+    std::map<eng::library_id_t, Gtk::TreeIter> m_albumsidmap;
 };
 
 }
diff --git a/src/rust_bindings.hpp b/src/rust_bindings.hpp
index e19e8e8..1d80d3f 100644
--- a/src/rust_bindings.hpp
+++ b/src/rust_bindings.hpp
@@ -52,6 +52,7 @@ using NiepcePropertyIdx = ffi::NiepcePropertyIdx;
 typedef ffi::LibraryId library_id_t; // XXX change this to LibraryId
 typedef ffi::FileType FileType;
 typedef ffi::FileStatus FileStatus;
+typedef ffi::Album Album;
 typedef ffi::Keyword Keyword;
 typedef ffi::LibFile LibFile;
 typedef ffi::LibFolder LibFolder;


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