[niepce] Issue #11 - Implement file info metadata panel
- From: Hubert Figuière <hub src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [niepce] Issue #11 - Implement file info metadata panel
- Date: Sun, 22 Apr 2018 00:07:40 +0000 (UTC)
commit 8cfebb2fac5955f01ddaf95f17747f25084d3811
Author: Hubert Figuière <hub figuiere net>
Date: Fri Mar 23 23:40:43 2018 -0400
Issue #11 - Implement file info metadata panel
- database version is now 8
- added readonly StringArray widget
- JPG and XMP sidecar are in the sidecar table
- Extended LibMetadata
https://gitlab.gnome.org/GNOME/niepce/issues/11
doc/database.txt | 5 ++-
src/engine/db/filebundle.rs | 18 +++++++++
src/engine/db/libmetadata.rs | 64 +++++++++++++++++++++++++-------
src/engine/db/library.rs | 56 +++++++++++++++++++++++-----
src/engine/db/metadata.hpp | 14 ++++++-
src/engine/db/properties-def.hpp | 12 ++++--
src/fwk/toolkit/metadatawidget.cpp | 6 ++-
src/fwk/toolkit/metadatawidget.hpp | 5 ++-
src/niepce/ui/metadatapanecontroller.cpp | 13 ++++++-
9 files changed, 159 insertions(+), 34 deletions(-)
---
diff --git a/doc/database.txt b/doc/database.txt
index a5ae145..48439cd 100644
--- a/doc/database.txt
+++ b/doc/database.txt
@@ -16,7 +16,7 @@ Files in the library
files id Unique ID in the database
main_file ID in fsfiles for the main file.
- path The absolute path to the file
+ name The (display) name of the file
parent_id The ID on the containing folder (= folders.id)
orientation The Exif orientation of the file
file_type The file type. See db::LibFile::FileType for
@@ -29,7 +29,7 @@ files id Unique ID in the database
import_date The date of import in the database (time_t)
mod_date The date modified (time_t)
xmp The XMP blob
- xmp_data The date the XMP is rewritten on disk (time_t)
+ xmp_date The date the XMP is rewritten on disk (time_t)
xmp_file The id of the fsfile that represent the XMP (int)
jpeg_file The id of the JPEG for RAW+JPEG. Implies
file_type is LibFile::FILE_TYPE_RAW_JPEG (int)
@@ -44,6 +44,7 @@ Sidecars are fsfiles attached to a file (excepted XMP and JPEG alternate).
sidecars file_id ID of the file.
fsfile_id ID of the fsfile sidecar.
+ ext String: the extension (no dot). [ version = 8 ]
type Sidecar type. 1 = Live, 2 = Thumbnail.
(See the Sidecar enum)
diff --git a/src/engine/db/filebundle.rs b/src/engine/db/filebundle.rs
index ed629a8..4dc28f3 100644
--- a/src/engine/db/filebundle.rs
+++ b/src/engine/db/filebundle.rs
@@ -32,6 +32,22 @@ pub enum Sidecar {
Live(String),
/// Thumbnail file (THM from Canon)
Thumbnail(String),
+ /// XMP Sidecar
+ Xmp(String),
+ /// JPEG Sidecar (RAW + JPEG)
+ Jpeg(String),
+}
+
+impl Sidecar {
+ pub fn to_int(&self) -> i32 {
+ match self {
+ &Sidecar::Live(_) => 1,
+ &Sidecar::Thumbnail(_) => 2,
+ &Sidecar::Xmp(_) => 3,
+ &Sidecar::Jpeg(_) => 4,
+ &Sidecar::Invalid => 0,
+ }
+ }
}
impl From<(i32, String)> for Sidecar {
@@ -39,6 +55,8 @@ impl From<(i32, String)> for Sidecar {
match t.0 {
1 => Sidecar::Live(t.1),
2 => Sidecar::Thumbnail(t.1),
+ 3 => Sidecar::Xmp(t.1),
+ 4 => Sidecar::Jpeg(t.1),
_ => Sidecar::Invalid,
}
}
diff --git a/src/engine/db/libmetadata.rs b/src/engine/db/libmetadata.rs
index 0b33c51..cf56e42 100644
--- a/src/engine/db/libmetadata.rs
+++ b/src/engine/db/libmetadata.rs
@@ -36,10 +36,15 @@ use super::{
LibraryId
};
use root::eng::NiepceProperties as Np;
+use engine::db::libfile::FileType;
pub struct LibMetadata {
xmp: XmpMeta,
- id: LibraryId
+ id: LibraryId,
+ pub sidecars: Vec<String>,
+ pub file_type: FileType,
+ pub name: String,
+ pub folder: String,
}
struct IndexToXmp {
@@ -60,18 +65,24 @@ fn property_index_to_xmp(meta: Np) -> Option<IndexToXmp> {
}
impl LibMetadata {
-
pub fn new(id: LibraryId) -> LibMetadata {
- LibMetadata{
+ LibMetadata {
xmp: XmpMeta::new(),
- id: id
+ id: id,
+ sidecars: vec![], file_type: FileType::UNKNOWN,
+ name: String::new(),
+ folder: String::new()
}
}
pub fn new_with_xmp(id: LibraryId, xmp: XmpMeta) -> LibMetadata {
- LibMetadata{
+ LibMetadata {
xmp: xmp,
- id: id
+ id: id,
+ sidecars: vec![],
+ file_type: FileType::UNKNOWN,
+ name: String::new(),
+ folder: String::new()
}
}
@@ -178,7 +189,28 @@ impl LibMetadata {
keywords.push(String::from(value.to_str()));
}
props.set_value(*prop_id, PropertyValue::StringArray(keywords));
- },
+ }
+ Np::NpFileNameProp => {
+ props.set_value(*prop_id, PropertyValue::String(self.name.clone()));
+ }
+ Np::NpFileTypeProp => {
+ // XXX this to string convert should be elsewhere
+ let file_type = match self.file_type {
+ FileType::UNKNOWN => "Unknown",
+ FileType::RAW => "RAW",
+ FileType::RAW_JPEG => "RAW + JPEG",
+ FileType::IMAGE => "Image",
+ FileType::VIDEO => "Video",
+ };
+ props.set_value(*prop_id, PropertyValue::String(String::from(file_type)));
+ }
+ Np::NpFileSizeProp => {}
+ Np::NpFolderProp => {
+ props.set_value(*prop_id, PropertyValue::String(self.folder.clone()));
+ }
+ Np::NpSidecarsProp => {
+ props.set_value(*prop_id, PropertyValue::StringArray(self.sidecars.clone()));
+ }
_ => {
if let Some(propval) = self.get_metadata(prop_id_np) {
props.set_value(*prop_id, propval);
@@ -193,19 +225,19 @@ impl LibMetadata {
pub fn touch(&mut self) -> bool {
let xmpdate = xmp_date_from(&Utc::now());
- return self.xmp.xmp.set_property_date(NS_XAP, "MetadataDate",
- &xmpdate, exempi::PROP_NONE);
+ return self.xmp
+ .xmp
+ .set_property_date(NS_XAP, "MetadataDate", &xmpdate, exempi::PROP_NONE);
}
}
impl FromDb for LibMetadata {
-
fn read_db_columns() -> &'static str {
- "id,xmp"
+ "files.id,xmp,file_type,files.name,folders.name"
}
fn read_db_tables() -> &'static str {
- "files"
+ "files LEFT JOIN folders ON folders.id = files.parent_id"
}
fn read_from(row: &rusqlite::Row) -> Self {
@@ -214,9 +246,13 @@ impl FromDb for LibMetadata {
let mut xmpmeta = XmpMeta::new();
xmpmeta.unserialize(&xmp);
- LibMetadata::new_with_xmp(id, xmpmeta)
+ let mut libmeta = LibMetadata::new_with_xmp(id, xmpmeta);
+ let col: i32 = row.get(2);
+ libmeta.file_type = FileType::from(col);
+ libmeta.name = row.get(3);
+ libmeta.folder = row.get(4);
+ libmeta
}
-
}
#[no_mangle]
diff --git a/src/engine/db/library.rs b/src/engine/db/library.rs
index 3f67f75..d53c55b 100644
--- a/src/engine/db/library.rs
+++ b/src/engine/db/library.rs
@@ -1,7 +1,7 @@
/*
* niepce - engine/db/library.rs
*
- * Copyright (C) 2017 Hubert Figuière
+ * Copyright (C) 2017-2018 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
@@ -46,7 +46,7 @@ pub enum Managed {
YES = 1,
}
-const DB_SCHEMA_VERSION: i32 = 7;
+const DB_SCHEMA_VERSION: i32 = 8;
const DATABASENAME: &str = "niepcelibrary.db";
pub struct Library {
@@ -183,7 +183,8 @@ impl Library {
// version = 7
conn.execute(
"CREATE TABLE sidecars (file_id INTEGER,\
- fsfile_id INTEGER, type INTEGER, UNIQUE(file_id, fsfile_id))",
+ fsfile_id INTEGER, type INTEGER, ext TEXT NOT NULL,\
+ UNIQUE(file_id, fsfile_id))",
&[],
).unwrap();
conn.execute(
@@ -276,18 +277,35 @@ impl Library {
pub fn add_sidecar_file_to_bundle(&self, file_id: LibraryId, sidecar: &Sidecar) -> bool {
let sidecar_t: (i32, &String) = match sidecar {
- &Sidecar::Live(ref p) => (1, p),
- &Sidecar::Thumbnail(ref p) => (2, p),
+ &Sidecar::Live(ref p)
+ | &Sidecar::Thumbnail(ref p)
+ | &Sidecar::Xmp(ref p)
+ | &Sidecar::Jpeg(ref p) => (sidecar.to_int(), p),
+ _ => return false,
+ };
+ let p = Path::new(sidecar_t.1);
+ let ext = match p.extension() {
+ Some(ext2) => ext2.to_string_lossy(),
_ => return false,
};
let fsfile_id = self.add_fs_file(&sidecar_t.1);
if fsfile_id == -1 {
return false;
}
+ self.add_sidecar_fsfile_to_bundle(file_id, fsfile_id, sidecar_t.0, &*ext)
+ }
+
+ fn add_sidecar_fsfile_to_bundle(
+ &self,
+ file_id: LibraryId,
+ fsfile_id: LibraryId,
+ sidecar_type: i32,
+ ext: &str,
+ ) -> bool {
if let Some(ref conn) = self.dbconn {
if let Ok(c) = conn.execute(
- "INSERT INTO sidecars (file_id, fsfile_id, type) VALUES(:1, :2, :3)",
- &[&file_id, &fsfile_id, &sidecar_t.0],
+ "INSERT INTO sidecars (file_id, fsfile_id, type, ext) VALUES(:1, :2, :3, :4)",
+ &[&file_id, &fsfile_id, &sidecar_type, &ext],
) {
if c == 1 {
return true;
@@ -474,12 +492,24 @@ impl Library {
let fsfile_id = self.add_fs_file(bundle.xmp_sidecar());
if fsfile_id > 0 {
self.add_xmp_sidecar_to_bundle(file_id, fsfile_id);
+ self.add_sidecar_fsfile_to_bundle(
+ file_id,
+ fsfile_id,
+ Sidecar::Xmp(String::new()).to_int(),
+ "xmp",
+ );
}
}
if !bundle.jpeg().is_empty() {
let fsfile_id = self.add_fs_file(bundle.jpeg());
if fsfile_id > 0 {
self.add_jpeg_file_to_bundle(file_id, fsfile_id);
+ self.add_sidecar_fsfile_to_bundle(
+ file_id,
+ fsfile_id,
+ Sidecar::Jpeg(String::new()).to_int(),
+ "jpg",
+ );
}
}
}
@@ -635,14 +665,22 @@ impl Library {
pub fn get_metadata(&self, file_id: LibraryId) -> Option<LibMetadata> {
let conn = try_opt!(self.dbconn.as_ref());
let sql = format!(
- "SELECT {} FROM {} WHERE id=:1",
+ "SELECT {} FROM {} WHERE files.id=:1",
LibMetadata::read_db_columns(),
LibMetadata::read_db_tables()
);
let mut stmt = try_opt!(conn.prepare(&sql).ok());
let mut rows = try_opt!(stmt.query(&[&file_id]).ok());
let row = try_opt!(try_opt!(rows.next()).ok());
- return Some(LibMetadata::read_from(&row));
+ let mut metadata = LibMetadata::read_from(&row);
+
+ let sql = "SELECT ext FROM sidecars WHERE file_id=:1";
+ let mut stmt = try_opt!(conn.prepare(&sql).ok());
+ let mut rows = try_opt!(stmt.query(&[&file_id]).ok());
+ while let Some(Ok(row)) = rows.next() {
+ metadata.sidecars.push(row.get(0));
+ }
+ return Some(metadata);
}
fn unassign_all_keywords_for_file(&self, file_id: LibraryId) -> bool {
diff --git a/src/engine/db/metadata.hpp b/src/engine/db/metadata.hpp
index e80856c..8818f65 100644
--- a/src/engine/db/metadata.hpp
+++ b/src/engine/db/metadata.hpp
@@ -29,7 +29,9 @@ enum {
META_NS_TIFF,
META_NS_EXIF,
META_NS_IPTC,
- META_NS_NIEPCE
+ META_NS_NIEPCE,
+
+ META_NS_INTERNAL = 0x0f00,
};
/** Metadata for xmpcore. Combine with %META_NS_XMPCORE */
@@ -81,6 +83,16 @@ enum {
META_NIEPCE_FLAG = 0
};
+
+/** Internal metadata */
+enum {
+ META_INTERNAL_FILENAME = 0,
+ META_INTERNAL_FILETYPE,
+ META_INTERNAL_FILESIZE,
+ META_INTERNAL_FOLDER,
+ META_INTERNAL_SIDECARS,
+};
+
/** make a metadata index with a namespace and a value */
#define MAKE_METADATA_IDX(x,y) (x<<16|y)
/** get the NS form the metadata index */
diff --git a/src/engine/db/properties-def.hpp b/src/engine/db/properties-def.hpp
index fdf0cbf..37ff0ea 100644
--- a/src/engine/db/properties-def.hpp
+++ b/src/engine/db/properties-def.hpp
@@ -1,7 +1,7 @@
/*
- * niepce - eng/db/proeprties-def.hpp
+ * niepce - eng/db/properties-def.hpp
*
- * Copyright (C) 2011 Hubert Figuiere
+ * Copyright (C) 2011-2018 Hubert Figuiere
*
* 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
@@ -21,13 +21,19 @@
#error DEFINE_PROPERTY must be defined
#endif
-// format is
+// format is
// - const
// - the value of the id
// - XMP NS - NULL if none
// - XMP property - NULL if none
// - type
+DEFINE_PROPERTY(NpFileNameProp, MAKE_METADATA_IDX(META_NS_INTERNAL, META_INTERNAL_FILENAME), nullptr,
nullptr, std::string)
+DEFINE_PROPERTY(NpFileTypeProp, MAKE_METADATA_IDX(META_NS_INTERNAL, META_INTERNAL_FILETYPE), nullptr,
nullptr, std::string)
+DEFINE_PROPERTY(NpFileSizeProp, MAKE_METADATA_IDX(META_NS_INTERNAL, META_INTERNAL_FILESIZE), nullptr,
nullptr, off_t)
+DEFINE_PROPERTY(NpFolderProp, MAKE_METADATA_IDX(META_NS_INTERNAL, META_INTERNAL_FOLDER), nullptr, nullptr,
std::string)
+DEFINE_PROPERTY(NpSidecarsProp, MAKE_METADATA_IDX(META_NS_INTERNAL, META_INTERNAL_SIDECARS), nullptr,
nullptr, std::vector<std::string>)
+
DEFINE_PROPERTY(NpXmpRatingProp, MAKE_METADATA_IDX(META_NS_XMPCORE, META_XMPCORE_RATING), NS_XAP, "Rating",
int32_t )
DEFINE_PROPERTY(NpXmpLabelProp, MAKE_METADATA_IDX(META_NS_XMPCORE, META_XMPCORE_LABEL), NS_XAP, "Label",
int32_t )
diff --git a/src/fwk/toolkit/metadatawidget.cpp b/src/fwk/toolkit/metadatawidget.cpp
index 39f846e..b393914 100644
--- a/src/fwk/toolkit/metadatawidget.cpp
+++ b/src/fwk/toolkit/metadatawidget.cpp
@@ -318,13 +318,15 @@ bool MetaDataWidget::set_star_rating_data(Gtk::Widget* w,
return true;
}
-bool MetaDataWidget::set_string_array_data(Gtk::Widget* w, const PropertyValuePtr& value)
+bool MetaDataWidget::set_string_array_data(Gtk::Widget* w, bool readonly,
+ const PropertyValuePtr& value)
{
try {
AutoFlag flag(m_update);
std::vector<std::string> tokens = fwk::property_value_get_string_array(*value);
static_cast<fwk::TokenTextView*>(w)->set_tokens(tokens);
+ static_cast<fwk::TokenTextView*>(w)->set_editable(!readonly);
}
catch(...) {
return false;
@@ -431,7 +433,7 @@ void MetaDataWidget::add_data(const MetaDataFormat * current,
set_star_rating_data(w, value);
break;
case MetaDT::STRING_ARRAY:
- set_string_array_data(w, value);
+ set_string_array_data(w, current->readonly, value);
break;
case MetaDT::TEXT:
set_text_data(w, current->readonly, value);
diff --git a/src/fwk/toolkit/metadatawidget.hpp b/src/fwk/toolkit/metadatawidget.hpp
index 8a45cd1..24459bd 100644
--- a/src/fwk/toolkit/metadatawidget.hpp
+++ b/src/fwk/toolkit/metadatawidget.hpp
@@ -44,7 +44,8 @@ enum class MetaDT {
DATE,
FRAC,
FRAC_DEC, // Fraction as decimal
- STAR_RATING
+ STAR_RATING,
+ SIZE, // Size in bytes
};
struct MetaDataFormat {
@@ -97,7 +98,7 @@ private:
// Fraction as fraction
bool set_fraction_data(Gtk::Widget* w, const PropertyValuePtr& value);
bool set_star_rating_data(Gtk::Widget* w, const PropertyValuePtr& value);
- bool set_string_array_data(Gtk::Widget* w, const PropertyValuePtr& value);
+ bool set_string_array_data(Gtk::Widget* w, bool readonly, const PropertyValuePtr& value);
bool set_text_data(Gtk::Widget* w, bool readonly,
const PropertyValuePtr& value);
bool set_string_data(Gtk::Widget* w, bool readonly,
diff --git a/src/niepce/ui/metadatapanecontroller.cpp b/src/niepce/ui/metadatapanecontroller.cpp
index 760bb22..a3aa3e0 100644
--- a/src/niepce/ui/metadatapanecontroller.cpp
+++ b/src/niepce/ui/metadatapanecontroller.cpp
@@ -1,7 +1,7 @@
/*
* niepce - niepce/ui/metadatapanecontroller.cpp
*
- * Copyright (C) 2008-2013 Hubert Figuiere
+ * Copyright (C) 2008-2018 Hubert Figuiere
*
* 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
@@ -32,6 +32,14 @@ namespace ui {
const fwk::MetaDataSectionFormat *
MetaDataPaneController::get_format()
{
+ static const fwk::MetaDataFormat s_fileinfo_format[] = {
+ { _("File Name:"), eng::NpFileNameProp, fwk::MetaDT::STRING, true },
+ { _("Folder:"), eng::NpFolderProp, fwk::MetaDT::STRING, true },
+ { _("File Type:"), eng::NpFileTypeProp, fwk::MetaDT::STRING, true },
+ { _("File Size:"), eng::NpFileSizeProp, fwk::MetaDT::SIZE, true },
+ { _("Sidecar Files:"), eng::NpSidecarsProp, fwk::MetaDT::STRING_ARRAY, true },
+ { nullptr, 0, fwk::MetaDT::NONE, true }
+ };
static const fwk::MetaDataFormat s_camerainfo_format[] = {
{ _("Make:"), eng::NpTiffMakeProp, fwk::MetaDT::STRING, true },
{ _("Model:"), eng::NpTiffModelProp, fwk::MetaDT::STRING, true },
@@ -61,6 +69,9 @@ MetaDataPaneController::get_format()
{ nullptr, 0, fwk::MetaDT::NONE, true }
};
static const fwk::MetaDataSectionFormat s_format[] = {
+ { _("File Information"),
+ s_fileinfo_format
+ },
{ _("Camera Information"),
s_camerainfo_format
},
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]