[niepce] Implement a generic properties system for editing. Move away from XMP. Implement the infrastructure



commit 89952409eef1cfa3fcb14a628fb73b0d9afce51d
Author: Hub Figuiere <hub figuiere net>
Date:   Fri Nov 11 15:19:30 2011 -0800

    Implement a generic properties system for editing.
    Move away from XMP.
    Implement the infrastructure for editing metadata in the UI.

 src/engine/db/Makefile.am                |    5 +-
 src/engine/db/metadata.hpp               |   39 ++++++-
 src/engine/db/properties-def.hpp         |   53 +++++++++
 src/engine/db/properties.cpp             |   47 ++++++++
 src/engine/db/properties.hpp             |   61 ++++++++++
 src/engine/db/xmpproperties.cpp          |  150 ++++++++++++++++++++++++
 src/engine/db/xmpproperties.hpp          |   59 +++++++++
 src/fwk/Makefile.am                      |    1 +
 src/fwk/base/propertybag.cpp             |   68 +++++++++++
 src/fwk/base/propertybag.hpp             |   76 ++++++++++++
 src/fwk/toolkit/metadatawidget.cpp       |  130 +++++++++++++--------
 src/fwk/toolkit/metadatawidget.hpp       |   50 ++++++--
 src/fwk/toolkit/widgets/ratinglabel.cpp  |    4 +-
 src/fwk/toolkit/widgets/ratinglabel.hpp  |    2 +-
 src/fwk/utils/exempi.hpp                 |   24 ----
 src/niepce/ui/gridviewmodule.cpp         |   12 ++
 src/niepce/ui/gridviewmodule.hpp         |    2 +
 src/niepce/ui/metadatapanecontroller.cpp |  188 ++++++++++++++++++------------
 src/niepce/ui/metadatapanecontroller.hpp |   14 ++-
 src/niepce/ui/selectioncontroller.cpp    |   24 ++++
 src/niepce/ui/selectioncontroller.hpp    |    3 +
 21 files changed, 839 insertions(+), 173 deletions(-)
---
diff --git a/src/engine/db/Makefile.am b/src/engine/db/Makefile.am
index 084d1fb..3c5d776 100644
--- a/src/engine/db/Makefile.am
+++ b/src/engine/db/Makefile.am
@@ -36,4 +36,7 @@ libniepcedb_a_SOURCES = library.hpp library.cpp \
 	storage.hpp storage.cpp \
 	fsfile.hpp fsfile.cpp \
 	filebundle.hpp filebundle.cpp \
-	metadata.hpp
+	metadata.hpp \
+	properties.hpp properties.cpp \
+	xmpproperties.hpp xmpproperties.cpp \
+	properties-def.hpp
diff --git a/src/engine/db/metadata.hpp b/src/engine/db/metadata.hpp
index 51b403e..08e4598 100644
--- a/src/engine/db/metadata.hpp
+++ b/src/engine/db/metadata.hpp
@@ -1,7 +1,7 @@
 /*
  * niepce - eng/db/metadata.hpp
  *
- * Copyright (C) 2008 Hubert Figuiere
+ * Copyright (C) 2008,2011 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
@@ -28,22 +28,53 @@ enum {
     META_NS_XMPCORE = 0,
     META_NS_TIFF,
     META_NS_EXIF,
+    META_NS_IPTC,
     META_NS_NIEPCE
 };
 
 /** Metadata for xmpcore. Combine with %META_NS_XMPCORE */
 enum {
-    META_XMPCORE_RATING = 0,
-    META_XMPCORE_LABEL = 1,
+    _META_XMPCORE_NONE_ = 0,
+    META_XMPCORE_RATING = 1,  // NS_XAP, "Rating"
+    META_XMPCORE_LABEL,       // NS_XAP, "Label"
 
     _META_XMPCORE_LAST_
 };
 
 /** Metadata for tiff. Combine with %META_NS_TIFF */
 enum {
-    META_TIFF_ORIENTATION = 0
+    META_TIFF_ORIENTATION = 0,
+    META_TIFF_MAKE,                // NS_TIFF, "Make"
+    META_TIFF_MODEL,               // NS_TIFF, "Model"
+
+    _META_TIFF_LAST_
+};
+
+enum {
+    META_EXIF_AUX_LENS = 0,            // NS_EXIF_AUX, "Lens"
+    META_EXIF_EXPOSUREPROGRAM,         // NS_EXIF, "ExposureProgram"
+    META_EXIF_EXPOSURETIME,            // NS_EXIF, "ExposureTime"
+    META_EXIF_FNUMBER,                 // NS_EXIF, "FNumber"
+    META_EXIF_ISOSPEEDRATINGS,         // NS_EXIF, "ISOSpeedRatings"
+    META_EXIF_EXPOSUREBIAS,            // NS_EXIF, "ExposureBiasValue"
+    META_EXIF_FLASHFIRED,              // NS_EXIF, "Flash/exif:Fired"
+    META_EXIF_AUX_FLASHCOMPENSATION,   // NS_EXIF_AUX, "FlashCompensation"
+    META_EXIF_WB,                      // NS_EXIF, "WhiteBalance"
+    META_EXIF_DATETIMEORIGINAL,        // NS_EXIF, "DateTimeOriginal"
+    META_EXIF_FOCALLENGTH,             // NS_EXIF, "FocalLength"
+    
+    _META_EXIF_LAST_
+};
+
+enum {
+    META_IPTC_HEADLINE = 0,    // NS_PHOTOSHOP, "Headline"
+    META_IPTC_DESCRIPTION = 1, // NS_DC, "description"
+    META_IPTC_KEYWORDS = 2,    // NS_DC, "subject"
+    
+    _META_IPTC_LAST_
 };
 
+/** Metadata for Niepce. Combine with %META_NS_NIEPCE */
 enum {
     META_NIEPCE_FLAG = 0
 };
diff --git a/src/engine/db/properties-def.hpp b/src/engine/db/properties-def.hpp
new file mode 100644
index 0000000..004b91e
--- /dev/null
+++ b/src/engine/db/properties-def.hpp
@@ -0,0 +1,53 @@
+/*
+ * niepce - eng/db/proeprties-def.hpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+#ifndef DEFINE_PROPERTY
+#error DEFINE_PROPERTY must be defined
+#endif
+
+// format is 
+// - const
+// - the value of the id
+// - XMP NS - NULL if none
+// - XMP property - NULL if none
+
+DEFINE_PROPERTY(NpXmpRatingProp, MAKE_METADATA_IDX(META_NS_XMPCORE, META_XMPCORE_RATING), NS_XAP, "Rating" )
+DEFINE_PROPERTY(NpXmpLabelProp,  MAKE_METADATA_IDX(META_NS_XMPCORE, META_XMPCORE_LABEL), NS_XAP, "Label" )
+
+DEFINE_PROPERTY(NpTiffOrientationProp, MAKE_METADATA_IDX(META_NS_TIFF, META_TIFF_ORIENTATION), NS_TIFF, "Orientation" )
+DEFINE_PROPERTY(NpTiffMakeProp, MAKE_METADATA_IDX(META_NS_TIFF, META_TIFF_MAKE), NS_TIFF, "Make" )
+DEFINE_PROPERTY(NpTiffModelProp, MAKE_METADATA_IDX(META_NS_TIFF, META_TIFF_MODEL), NS_TIFF, "Model" )
+
+DEFINE_PROPERTY(NpExifAuxLensProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_AUX_LENS), NS_EXIF_AUX, "Lens" )
+DEFINE_PROPERTY(NpExifExposureProgramProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_EXPOSUREPROGRAM), NS_EXIF, "ExposureProgram")
+DEFINE_PROPERTY(NpExifExposureTimeProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_EXPOSURETIME), NS_EXIF, "ExposureTime")
+DEFINE_PROPERTY(NpExifFNumberPropProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_FNUMBER), NS_EXIF, "FNumber")
+DEFINE_PROPERTY(NpExifIsoSpeedRatingsProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_ISOSPEEDRATINGS), NS_EXIF, "ISOSpeedRatings")
+DEFINE_PROPERTY(NpExifExposureBiasProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_EXPOSUREBIAS), NS_EXIF, "ExposureBiasValue")
+DEFINE_PROPERTY(NpExifFlashFiredProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_FLASHFIRED), NS_EXIF, "Flash/exif:Fired")
+DEFINE_PROPERTY(NpExifAuxFlashCompensationProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_AUX_FLASHCOMPENSATION), NS_EXIF_AUX, "FlashCompensation")
+DEFINE_PROPERTY(NpExifWbProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_WB), NS_EXIF, "WhiteBalance")
+DEFINE_PROPERTY(NpExifDateTimeOriginalProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_DATETIMEORIGINAL), NS_EXIF, "DateTimeOriginal")
+DEFINE_PROPERTY(NpExifFocalLengthProp, MAKE_METADATA_IDX(META_NS_EXIF, META_EXIF_FOCALLENGTH), NS_EXIF, "FocalLength")
+
+DEFINE_PROPERTY(NpIptcHeadlineProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_HEADLINE), NS_PHOTOSHOP, "Headline")
+DEFINE_PROPERTY(NpIptcDescriptionProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_DESCRIPTION), NS_DC, "description")
+DEFINE_PROPERTY(NpIptcKeywordsProp, MAKE_METADATA_IDX(META_NS_IPTC, META_IPTC_KEYWORDS), NS_DC, "subject")
+
+DEFINE_PROPERTY(NpNiepceFlagProp, MAKE_METADATA_IDX(META_NS_NIEPCE, META_NIEPCE_FLAG), xmp::NIEPCE_XMP_NAMESPACE, "Flag")
diff --git a/src/engine/db/properties.cpp b/src/engine/db/properties.cpp
new file mode 100644
index 0000000..ccdc4d0
--- /dev/null
+++ b/src/engine/db/properties.cpp
@@ -0,0 +1,47 @@
+/*
+ * niepce - eng/db/properties.cpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+#include "properties.hpp"
+
+
+namespace eng {
+
+#define DEFINE_PROPERTY(a,b,c,d)			\
+    { a, #a },
+
+const property_desc_t properties_names[] = {
+
+    #include "engine/db/properties-def.hpp"
+
+    { 0, NULL }
+};
+
+#undef DEFINE_PROPERTY
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
diff --git a/src/engine/db/properties.hpp b/src/engine/db/properties.hpp
new file mode 100644
index 0000000..3df1b21
--- /dev/null
+++ b/src/engine/db/properties.hpp
@@ -0,0 +1,61 @@
+/*
+ * niepce - eng/db/properties.hpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+
+#ifndef __ENG_PROPERTIES_HPP__
+#define __ENG_PROPERTIES_HPP__
+
+#include "fwk/base/propertybag.hpp"
+#include "engine/db/metadata.hpp"
+
+namespace eng {
+
+  // prefix Np is for Niepce Property
+
+#define DEFINE_PROPERTY(a,b,c,d)                 \
+    a = b,
+
+enum {
+
+    #include "engine/db/properties-def.hpp"
+
+    _NpLastProp
+};
+
+#undef DEFINE_PROPERTY
+
+struct property_desc_t {
+    fwk::PropertyIndex prop;
+    const char * name;
+};
+
+extern const property_desc_t properties_names[];
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
+#endif
diff --git a/src/engine/db/xmpproperties.cpp b/src/engine/db/xmpproperties.cpp
new file mode 100644
index 0000000..f08eb55
--- /dev/null
+++ b/src/engine/db/xmpproperties.cpp
@@ -0,0 +1,150 @@
+/*
+ * niepce - eng/db/xmpproperties.hpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+#include <exempi/xmpconsts.h>
+
+#include "fwk/base/debug.hpp"
+#include "fwk/base/propertybag.hpp"
+#include "fwk/utils/stringutils.hpp"
+#include "fwk/utils/exempi.hpp"
+
+#include "properties.hpp"
+#include "xmpproperties.hpp"
+
+
+namespace eng {
+
+const PropsToXmpMap & props_to_xmp_map()
+{
+    static PropsToXmpMap s_props_map;
+    if(s_props_map.empty()) {
+
+#define DEFINE_PROPERTY(a,b,c,d) \
+        s_props_map.insert(std::make_pair(b, std::make_pair(c,d)));
+#include "engine/db/properties-def.hpp"
+#undef DEFINE_PROPERTY
+
+    }
+    return s_props_map;
+}
+
+bool get_prop_from_xmp(const fwk::XmpMeta * meta, fwk::PropertyIndex p, 
+                       fwk::PropertyValue & value)
+{
+    const PropsToXmpMap & propmap = props_to_xmp_map();
+    PropsToXmpMap::const_iterator iter = propmap.find(p);
+    if(iter == propmap.end()) {
+        // not found
+        return false;
+    }
+    if(iter->second.first == NULL || iter->second.second == NULL) {
+        // no XMP equivalent
+        return false;
+    }
+    xmp::ScopedPtr<XmpStringPtr> xmp_value(xmp_string_new());
+    if(xmp_get_property(meta->xmp(), iter->second.first,
+                        iter->second.second, xmp_value, NULL)) {
+        const char * v = NULL;
+        v = xmp_string_cstr(xmp_value);
+        if(v) {
+            value = fwk::PropertyValue(v);
+            return true;
+        }
+    }
+    // not found in XMP
+    return false;
+}
+
+void convert_xmp_to_properties(const fwk::XmpMeta * meta, const fwk::PropertySet & propset,
+                               fwk::PropertyBag & properties)
+{
+    if(meta == NULL) {
+        ERR_OUT("invalid passing NULL meta");
+        return;
+    }
+    fwk::PropertySet::const_iterator iter;
+    xmp::ScopedPtr<XmpStringPtr> value(xmp_string_new());
+    fwk::PropertyValue propval;
+    for(iter = propset.begin(); iter != propset.end(); ++iter) {
+        switch(*iter) {
+        case NpXmpRatingProp:
+            properties.set_value_for_property(NpXmpRatingProp,
+                                              fwk::PropertyValue(meta->rating()));
+            break;
+        case NpXmpLabelProp:
+            properties.set_value_for_property(NpXmpLabelProp,
+                                              fwk::PropertyValue(meta->label()));
+            break;
+        case NpTiffOrientationProp:
+            properties.set_value_for_property(NpTiffOrientationProp, 
+                                              fwk::PropertyValue(meta->orientation()));
+            break;
+        case NpIptcKeywordsProp:
+        {
+            xmp::ScopedPtr<XmpIteratorPtr> 
+                iter(xmp_iterator_new(meta->xmp(), NS_DC,
+                                      "subject", XMP_ITER_JUSTLEAFNODES));
+            std::vector<std::string> vec;
+            while(xmp_iterator_next(iter, NULL, NULL, value, NULL)) {
+                vec.push_back(xmp_string_cstr(value));
+            }
+            std::string v = fwk::join(vec, ", ");
+            properties.set_value_for_property(NpIptcKeywordsProp, 
+                                              fwk::PropertyValue(v));
+            break;
+        }
+        default:
+            if(get_prop_from_xmp(meta, *iter, propval)) {
+                properties.set_value_for_property(*iter, propval);                
+            }
+            else {
+                DBG_OUT("unknown prop %u", *iter);
+            }
+            break;
+        }
+    }
+}
+
+#if 0
+
+if(current->type == META_DT_STRING_ARRAY) {
+    xmp::ScopedPtr<XmpIteratorPtr> 
+        iter(xmp_iterator_new(xmp->xmp(), current->ns,
+                              current->property, XMP_ITER_JUSTLEAFNODES));
+    std::vector<std::string> vec;
+    while(xmp_iterator_next(iter, NULL, NULL, value, NULL)) {
+        vec.push_back(xmp_string_cstr(value));
+    }
+    std::string v = fwk::join(vec, ", ");
+    add_data(current, v.c_str());
+}
+
+#endif
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
diff --git a/src/engine/db/xmpproperties.hpp b/src/engine/db/xmpproperties.hpp
new file mode 100644
index 0000000..4929f93
--- /dev/null
+++ b/src/engine/db/xmpproperties.hpp
@@ -0,0 +1,59 @@
+/*
+ * niepce - eng/db/xmpproperties.hpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+
+
+
+#ifndef __ENG_XMPPROPERTIES_HPP__
+#define __ENG_XMPPROPERTIES_HPP__
+
+#include <map>
+#include "fwk/base/propertybag.hpp"
+
+namespace fwk {
+class XmpMeta;
+}
+
+namespace eng {
+
+typedef std::map<fwk::PropertyIndex, std::pair<const char*, const char *> > PropsToXmpMap;
+
+/** get the mapping of properties to XMP */
+const PropsToXmpMap & props_to_xmp_map();
+
+/** convert XMP to a set of properties 
+ * @param meta the XmpMeta source
+ * @param propset the property set requested
+ * @param props the output properties
+ */
+void convert_xmp_to_properties(const fwk::XmpMeta * meta, 
+			       const fwk::PropertySet & propset, fwk::PropertyBag & props);
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+#endif
diff --git a/src/fwk/Makefile.am b/src/fwk/Makefile.am
index 615b380..1013211 100644
--- a/src/fwk/Makefile.am
+++ b/src/fwk/Makefile.am
@@ -29,4 +29,5 @@ libfwk_a_SOURCES = base/color.hpp base/color.cpp \
 	base/geometry.hpp base/geometry.cpp \
 	base/singleton.hpp \
 	base/map.hpp \
+	base/propertybag.hpp base/propertybag.cpp \
 	$(NULL)
diff --git a/src/fwk/base/propertybag.cpp b/src/fwk/base/propertybag.cpp
new file mode 100644
index 0000000..2d6adb6
--- /dev/null
+++ b/src/fwk/base/propertybag.cpp
@@ -0,0 +1,68 @@
+/*
+ * niepce - fwk/base/propertybag.cpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+
+
+#include "propertybag.hpp"
+
+namespace fwk {
+
+bool PropertyBag::set_value_for_property(PropertyIndex idx, const PropertyValue & value)
+{
+    bool removed = (m_bag.erase(idx) == 1);
+    m_bag.insert(std::make_pair(idx, value));
+    return removed;
+}
+
+/** return true if a property is found */
+bool PropertyBag::get_value_for_property(PropertyIndex idx, PropertyValue & value) const
+{
+    _Map::const_iterator iter = m_bag.find(idx);
+    if(iter == m_bag.end()) {
+        return false;
+    }
+    value = iter->second;
+    return true;
+}
+
+
+bool PropertyBag::has_value_for_property(PropertyIndex idx) const
+{
+    return m_bag.find(idx) != m_bag.end();
+}
+
+
+bool PropertyBag::remove_value_for_property(PropertyIndex idx)
+{
+    _Map::size_type sz = m_bag.erase(idx);
+    return sz == 1;
+}
+
+
+
+}
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
diff --git a/src/fwk/base/propertybag.hpp b/src/fwk/base/propertybag.hpp
new file mode 100644
index 0000000..4200ac5
--- /dev/null
+++ b/src/fwk/base/propertybag.hpp
@@ -0,0 +1,76 @@
+/*
+ * niepce - fwk/base/propertybag.cpp
+ *
+ * Copyright (C) 2011 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
+ * 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/>.
+ */
+
+
+
+#ifndef __FWK_PROPERTYBAG_HPP_
+#define __FWK_PROPERTYBAG_HPP_
+
+#include <map>
+#include <set>
+#include <tr1/memory>
+#include <boost/variant.hpp>
+
+namespace fwk {
+
+typedef uint32_t PropertyIndex;
+typedef boost::variant<int, std::string> PropertyValue;
+
+typedef std::set<PropertyIndex> PropertySet;
+
+/** a property bag 
+ * It is important that the values for PropertyIndex be properly name spaced
+ * by the caller.
+ */
+class PropertyBag
+{
+public:
+    typedef std::tr1::shared_ptr<PropertyBag> Ptr;
+
+    bool empty() const
+        {
+            return m_bag.empty();
+        }
+
+    /** return true if a property was removed prior to insertion */
+    bool set_value_for_property(PropertyIndex idx, const PropertyValue & value);
+    /** return true if a property is found */
+    bool get_value_for_property(PropertyIndex idx, PropertyValue & value) const;
+    /** return true if property exist */
+    bool has_value_for_property(PropertyIndex idx) const;
+    /** return true if the property was removed */
+    bool remove_value_for_property(PropertyIndex idx);
+private:
+    typedef std::map<PropertyIndex, PropertyValue> _Map;
+    _Map    m_bag;
+};
+
+
+}
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+#endif
diff --git a/src/fwk/toolkit/metadatawidget.cpp b/src/fwk/toolkit/metadatawidget.cpp
index 4f92484..35e0c61 100644
--- a/src/fwk/toolkit/metadatawidget.cpp
+++ b/src/fwk/toolkit/metadatawidget.cpp
@@ -24,6 +24,7 @@
 #include <boost/bind.hpp>
 #include <glibmm/i18n.h>
 #include <gtkmm/label.h>
+#include <gtkmm/entry.h>
 
 #include "fwk/base/debug.hpp"
 #include "fwk/base/fractions.hpp"
@@ -31,6 +32,9 @@
 #include "fwk/utils/stringutils.hpp"
 #include "fwk/toolkit/widgets/ratinglabel.hpp"
 
+// remove
+#include "engine/db/properties.hpp"
+
 #include "metadatawidget.hpp"
 
 
@@ -45,20 +49,25 @@ MetaDataWidget::MetaDataWidget(const Glib::ustring & title)
     add(m_table);
 }
 
-void MetaDataWidget::set_data_format(const xmp::MetaDataSectionFormat * fmt)
+void MetaDataWidget::set_data_format(const MetaDataSectionFormat * fmt)
 {
     m_fmt = fmt;
 }
 
 namespace {
 static 
-void clear_widget(std::pair<const std::string, Gtk::Widget *> & p)
+void clear_widget(std::pair<const PropertyIndex, Gtk::Widget *> & p)
 {
     Gtk::Label * l = dynamic_cast<Gtk::Label*>(p.second);
     if(l) {
         l->set_text("");
         return;
     }
+    Gtk::Entry * e = dynamic_cast<Gtk::Entry*>(p.second);
+    if(e) {
+        e->set_text("");
+        return;
+    }
     fwk::RatingLabel * rl = dynamic_cast<fwk::RatingLabel*>(p.second);
     if(rl) {
         rl->set_rating(0);
@@ -67,14 +76,14 @@ void clear_widget(std::pair<const std::string, Gtk::Widget *> & p)
 }
 }
 
-void MetaDataWidget::set_data_source(const fwk::XmpMeta * xmp)
+void MetaDataWidget::set_data_source(const fwk::PropertyBag & properties)
 {
     DBG_OUT("set data source");
     if(!m_data_map.empty()) {
         std::for_each(m_data_map.begin(), m_data_map.end(),
                       boost::bind(&clear_widget, _1));
     }
-    if(!xmp) {
+    if(properties.empty()) {
         return;
     }
     if(!m_fmt) {
@@ -82,71 +91,71 @@ void MetaDataWidget::set_data_source(const fwk::XmpMeta * xmp)
         return;
     }
 
-    const xmp::MetaDataFormat * current = m_fmt->formats;
+    const MetaDataFormat * current = m_fmt->formats;
     xmp::ScopedPtr<XmpStringPtr> value(xmp_string_new());
     while(current && current->label) {
-        std::string id(current->property);
-        id += "-";
-        id += current->ns;
-        if(current->type == xmp::META_DT_STRING_ARRAY) {
-            xmp::ScopedPtr<XmpIteratorPtr> 
-                iter(xmp_iterator_new(xmp->xmp(), current->ns,
-                                      current->property, XMP_ITER_JUSTLEAFNODES));
-            std::vector<std::string> vec;
-            while(xmp_iterator_next(iter, NULL, NULL, value, NULL)) {
-                vec.push_back(xmp_string_cstr(value));
-            }
-            std::string v = fwk::join(vec, ", ");
-            add_data(id, current->label, v.c_str(), current->type);
+        PropertyValue v;
+        if(properties.get_value_for_property(current->id, v)) {
+            add_data(current, v);
         }
         else {
-            const char * v = "";
-            if(xmp_get_property(xmp->xmp(), current->ns,
-                                current->property, value, NULL)) {
-                v = xmp_string_cstr(value);
-            }
-            else {
-                DBG_OUT("get_property failed id = %s, ns = %s, prop = %s,"
-                        "label = %s",
-                        id.c_str(), current->ns, current->property,
-                        current->label);
-            }
-            add_data(id, current->label, v, current->type);
+            DBG_OUT("get_property failed id = %d, label = %s",
+                    current->id, current->label);
         }
         current++;
     }
 }
 
 
-void MetaDataWidget::add_data(const std::string & id, 
-                              const std::string & label,
-                              const char * value,
-                              xmp::MetaDataType type)
+void MetaDataWidget::add_data(const MetaDataFormat * current,
+                              const PropertyValue & value)
 {
     Gtk::Widget *w = NULL;
     int n_row;
-    std::map<std::string, Gtk::Widget *>::iterator iter 
+    std::map<PropertyIndex, Gtk::Widget *>::iterator iter 
         = m_data_map.end();
     if(m_data_map.empty()) {
         n_row = 0;
     }
     else {
-        iter = m_data_map.find(id);
+        iter = m_data_map.find(current->id);
         n_row = m_table.property_n_rows();
     }
     if(iter == m_data_map.end()) {
         Gtk::Label *labelw = Gtk::manage(new Gtk::Label(
                                              Glib::ustring("<b>") 
-                                             + label + "</b>"));
+                                             + current->label + "</b>"));
         labelw->set_alignment(0.0f, 0.5f);
         labelw->set_use_markup(true);
 
-        if(type == xmp::META_DT_STAR_RATING) {
-            w = Gtk::manage(new fwk::RatingLabel());
+        if(current->type == META_DT_STAR_RATING) {
+            fwk::RatingLabel * r = Gtk::manage(new fwk::RatingLabel(0, !current->readonly));
+            if(!current->readonly) {
+                r->signal_changed.connect(
+                    sigc::bind(
+                        sigc::mem_fun(*this, 
+                                      &MetaDataWidget::on_int_changed), 
+                        current->id));
+            }
+            w = r;
         }
         else {
-            w = Gtk::manage(new Gtk::Label());
-            static_cast<Gtk::Label*>(w)->set_alignment(0.0f, 0.5f);
+            // TODO make it editable
+
+            if(current->readonly) {
+                Gtk::Label * l = Gtk::manage(new Gtk::Label());
+                l->set_alignment(0.0f, 0.5f);
+                w = l;
+            }
+            else {
+                Gtk::Entry * e = Gtk::manage(new Gtk::Entry());
+                e->signal_changed().connect(
+                    sigc::bind(
+                        sigc::mem_fun(*this, 
+                                      &MetaDataWidget::on_str_changed),
+                        e, current->id));
+                w = e;
+            }
         }
 
         m_table.resize(n_row + 1, 2);
@@ -154,42 +163,61 @@ void MetaDataWidget::add_data(const std::string & id,
                        Gtk::FILL, Gtk::SHRINK, 4, 0);
         m_table.attach(*w, 1, 2, n_row, n_row+1, 
                        Gtk::EXPAND|Gtk::FILL, Gtk::SHRINK, 4, 0);
-        m_data_map.insert(std::make_pair(id, w));
+        m_data_map.insert(std::make_pair(current->id, w));
     }
     else {
         w = static_cast<Gtk::Label*>(iter->second);
     }
-    switch(type) {
-    case xmp::META_DT_FRAC:
+    switch(current->type) {
+    case META_DT_FRAC:
     {
         try {
-            double decimal = fwk::fraction_to_decimal(value);
+            double decimal = fwk::fraction_to_decimal(boost::get<std::string>(value));
             std::string frac = boost::lexical_cast<std::string>(decimal);
             static_cast<Gtk::Label*>(w)->set_text(frac);
         }
         catch(...) {
-            DBG_OUT("conversion of '%s' to frac failed", value);
+            DBG_OUT("conversion of '%u' to frac failed", current->id);
         }
         break;
     }
-    case xmp::META_DT_STAR_RATING:
+    case META_DT_STAR_RATING:
     {
         try {
-            int rating = boost::lexical_cast<int>(value);
+            int rating = boost::get<int>(value);
             static_cast<fwk::RatingLabel*>(w)->set_rating(rating);
         }
         catch(...) {
-            DBG_OUT("conversion of '%s' to int failed", value);
+            DBG_OUT("conversion of '%u' to int failed", current->id);
         }
         break;
     }
-    default:
-        static_cast<Gtk::Label*>(w)->set_text(value);
+    default:        
+        if(current->readonly) {
+            static_cast<Gtk::Label*>(w)->set_text(boost::get<std::string>(value));
+        }
+        else {
+            static_cast<Gtk::Entry*>(w)->set_text(boost::get<std::string>(value));
+        }
         break;
     }
     m_table.show_all();
 }
 
+void MetaDataWidget::on_str_changed(Gtk::Entry *e, fwk::PropertyIndex prop)
+{
+    fwk::PropertyBag props;
+    props.set_value_for_property(prop, fwk::PropertyValue(e->get_text()));
+    signal_metadata_changed.emit(props);
+}
+
+void MetaDataWidget::on_int_changed(int value, fwk::PropertyIndex prop)
+{
+    fwk::PropertyBag props;
+    props.set_value_for_property(prop, fwk::PropertyValue(value));
+    signal_metadata_changed.emit(props);
+}
+
 }
 
 /*
diff --git a/src/fwk/toolkit/metadatawidget.hpp b/src/fwk/toolkit/metadatawidget.hpp
index cd163d6..f7997cd 100644
--- a/src/fwk/toolkit/metadatawidget.hpp
+++ b/src/fwk/toolkit/metadatawidget.hpp
@@ -26,32 +26,60 @@
 
 #include <gtkmm/table.h>
 
+#include "fwk/base/propertybag.hpp"
 #include "fwk/toolkit/widgets/toolboxitemwidget.hpp"
 
 namespace xmp {
-	struct MetaDataSectionFormat;
+struct MetaDataSectionFormat;
+struct MetaDataFormat;
 }
 
 namespace fwk {
 
-class XmpMeta;
+enum MetaDataType {
+    META_DT_NONE = 0,
+    META_DT_STRING,
+    META_DT_STRING_ARRAY,
+    META_DT_TEXT,
+    META_DT_DATE,
+    META_DT_FRAC, 
+    META_DT_STAR_RATING
+};
 
+struct MetaDataFormat {
+    const char * label;
+    uint32_t     id;
+    MetaDataType type;
+    bool         readonly;
+};
+	
+struct MetaDataSectionFormat {
+    const char * section;
+    const MetaDataFormat * formats;
+};
+
+
+class XmpMeta;
 
 class MetaDataWidget 
 	: public fwk::ToolboxItemWidget
 {
 public:
-	MetaDataWidget(const Glib::ustring & title);
-	
-	void add_data(const std::string & id, const std::string & label,
-				  const char * value, xmp::MetaDataType type);
-	void set_data_format(const xmp::MetaDataSectionFormat * fmt);
-	void set_data_source(const fwk::XmpMeta * xmp);
+    MetaDataWidget(const Glib::ustring & title);
+    
+    void add_data(const MetaDataFormat * current,
+                  const PropertyValue & value);
+    void set_data_format(const MetaDataSectionFormat * fmt);
+    void set_data_source(const fwk::PropertyBag & properties);
+    
+    sigc::signal<void, const fwk::PropertyBag &> signal_metadata_changed;
 protected:
+    void on_str_changed(Gtk::Entry *, fwk::PropertyIndex prop);
+    void on_int_changed(int, fwk::PropertyIndex prop);
 private:
-	Gtk::Table    m_table;
-	std::map<std::string, Gtk::Widget *> m_data_map;
-	const xmp::MetaDataSectionFormat * m_fmt;
+    Gtk::Table    m_table;
+    std::map<const PropertyIndex, Gtk::Widget *> m_data_map;
+    const MetaDataSectionFormat * m_fmt;
 };
 
 }
diff --git a/src/fwk/toolkit/widgets/ratinglabel.cpp b/src/fwk/toolkit/widgets/ratinglabel.cpp
index c4489c7..252277c 100644
--- a/src/fwk/toolkit/widgets/ratinglabel.cpp
+++ b/src/fwk/toolkit/widgets/ratinglabel.cpp
@@ -93,10 +93,10 @@ int RatingLabel::rating_value_from_hit_x(double x)
   return round(x / width);
 }
 
-RatingLabel::RatingLabel(int rating)
+  RatingLabel::RatingLabel(int rating, bool editable)
   : Gtk::DrawingArea()
   , m_rating(rating)
-  , m_is_editable(false)
+  , m_is_editable(editable)
 {
   DBG_OUT("ctor");
 }
diff --git a/src/fwk/toolkit/widgets/ratinglabel.hpp b/src/fwk/toolkit/widgets/ratinglabel.hpp
index 0f7e628..51f8445 100644
--- a/src/fwk/toolkit/widgets/ratinglabel.hpp
+++ b/src/fwk/toolkit/widgets/ratinglabel.hpp
@@ -29,7 +29,7 @@ class RatingLabel
   : public Gtk::DrawingArea
 {
 public:
-  RatingLabel(int rating = 0);
+  RatingLabel(int rating = 0, bool editable = true);
   virtual ~RatingLabel();
 
   bool is_editable() const
diff --git a/src/fwk/utils/exempi.hpp b/src/fwk/utils/exempi.hpp
index d4de3c8..df63f4c 100644
--- a/src/fwk/utils/exempi.hpp
+++ b/src/fwk/utils/exempi.hpp
@@ -75,30 +75,6 @@ private:
     T _p;
 };
 
-
-enum MetaDataType {
-    META_DT_NONE = 0,
-    META_DT_STRING,
-    META_DT_STRING_ARRAY,
-    META_DT_DATE,
-    META_DT_FRAC, 
-    META_DT_STAR_RATING
-};
-	
-	
-struct MetaDataFormat {
-    const char * label;
-    const char * ns;
-    const char * property;
-    MetaDataType     type;
-    bool         readonly;
-};
-	
-struct MetaDataSectionFormat {
-    const char * section;
-    const MetaDataFormat * formats;
-};
-
 extern const char * NIEPCE_XMP_NAMESPACE;
 extern const char * NIEPCE_XMP_NS_PREFIX;
 extern const char * UFRAW_INTEROP_NAMESPACE;	
diff --git a/src/niepce/ui/gridviewmodule.cpp b/src/niepce/ui/gridviewmodule.cpp
index d473a77..ae28307 100644
--- a/src/niepce/ui/gridviewmodule.cpp
+++ b/src/niepce/ui/gridviewmodule.cpp
@@ -22,6 +22,8 @@
 #include <gtkmm/treestore.h>
 #include <gtkmm/treeselection.h>
 
+#include <exempi/xmpconsts.h>
+
 #include "fwk/base/debug.hpp"
 #include "fwk/toolkit/application.hpp"
 #include "fwk/toolkit/configdatabinder.hpp"
@@ -111,6 +113,8 @@ Gtk::Widget * GridViewModule::buildWidget(const Glib::RefPtr<Gtk::UIManager> & m
   m_lib_splitview.pack1(m_scrollview);
   m_dock = new fwk::Dock();
   m_metapanecontroller = MetaDataPaneController::Ptr(new MetaDataPaneController);
+  m_metapanecontroller->signal_metadata_changed.connect(
+      sigc::mem_fun(*this, &GridViewModule::on_metadata_changed));
   add(m_metapanecontroller);
   m_lib_splitview.pack2(*m_dock);
   m_dock->vbox().pack_start(*m_metapanecontroller->buildWidget(manager));
@@ -171,6 +175,14 @@ void GridViewModule::select_image(eng::library_id_t id)
     }
 }
 
+
+void GridViewModule::on_metadata_changed(const fwk::PropertyBag & props)
+{
+    // TODO this MUST be more generic
+    DBG_OUT("on_metadata_changed()");
+    m_shell.get_selection_controller()->set_properties(props);
+}
+
 void GridViewModule::on_rating_changed(int /*id*/, int rating)
 {
     m_shell.get_selection_controller()->set_rating(rating);
diff --git a/src/niepce/ui/gridviewmodule.hpp b/src/niepce/ui/gridviewmodule.hpp
index 665c57b..b95e5c7 100644
--- a/src/niepce/ui/gridviewmodule.hpp
+++ b/src/niepce/ui/gridviewmodule.hpp
@@ -28,6 +28,7 @@
 #include <gtkmm/liststore.h>
 #include <gtkmm/treestore.h>
 
+#include "fwk/base/propertybag.hpp"
 #include "engine/db/library.hpp"
 #include "niepce/ui/ilibrarymodule.hpp"
 #include "niepce/ui/imoduleshell.hpp"
@@ -74,6 +75,7 @@ protected:
 
 
 private:
+  void on_metadata_changed(const fwk::PropertyBag &);
   void on_rating_changed(int id, int rating);
 
   const IModuleShell &               m_shell;
diff --git a/src/niepce/ui/metadatapanecontroller.cpp b/src/niepce/ui/metadatapanecontroller.cpp
index f4bef64..b721fa5 100644
--- a/src/niepce/ui/metadatapanecontroller.cpp
+++ b/src/niepce/ui/metadatapanecontroller.cpp
@@ -24,109 +24,149 @@
 #include <gtkmm/entry.h>
 #include <gtkmm/stock.h>
 
-#include <exempi/xmpconsts.h>
-
 #include "fwk/base/debug.hpp"
-#include "fwk/utils/exempi.hpp"
 #include "fwk/toolkit/metadatawidget.hpp"
+#include "engine/db/properties.hpp"
+#include "engine/db/xmpproperties.hpp"
 #include "metadatapanecontroller.hpp"
 
-using namespace xmp;
-
 namespace ui {
-
 	
-  const MetaDataSectionFormat *
-  MetaDataPaneController::get_format() 
-  {
-    static const MetaDataFormat s_camerainfo_format[] = {
-      { _("Make:"), NS_TIFF, "Make", META_DT_STRING, true },
-      { _("Model:"), NS_TIFF, "Model", META_DT_STRING, true },
-      { _("Lens:"), NS_EXIF_AUX, "Lens", META_DT_STRING, true },
-      { NULL, NULL, NULL, META_DT_NONE, true }
+const fwk::MetaDataSectionFormat *
+MetaDataPaneController::get_format() 
+{
+    static const fwk::MetaDataFormat s_camerainfo_format[] = {
+        { _("Make:"), eng::NpTiffMakeProp, fwk::META_DT_STRING, true },
+        { _("Model:"), eng::NpTiffModelProp, fwk::META_DT_STRING, true },
+        { _("Lens:"), eng::NpExifAuxLensProp, fwk::META_DT_STRING, true },
+        { NULL, 0, fwk::META_DT_NONE, true }
     };
-    static const MetaDataFormat s_shootinginfo_format[] = {
-      { _("Exposure Program:"), NS_EXIF, "ExposureProgram", META_DT_STRING, true },
-      { _("Speed:"), NS_EXIF, "ExposureTime", META_DT_STRING, true },
-      { _("Aperture:"), NS_EXIF, "FNumber", META_DT_FRAC, true },
-      { _("ISO:"), NS_EXIF, "ISOSpeedRatings", META_DT_STRING_ARRAY, true },
-      { _("Exposure Bias:"), NS_EXIF, "ExposureBiasValue", META_DT_FRAC, true },
-      // this one is fishy as it hardcode the prefix.
-      { _("Flash:"), NS_EXIF, "Flash/exif:Fired", META_DT_STRING, true },
-      { _("Flash compensation:"), NS_EXIF_AUX, "FlashCompensation", META_DT_STRING, true },
-      { _("Focal length:"), NS_EXIF, "FocalLength", META_DT_FRAC, true },
-      { _("White balance:"), NS_EXIF, "WhiteBalance", META_DT_STRING, true },
-      { _("Date:"), NS_EXIF, "DateTimeOriginal", META_DT_DATE, false },
-      { NULL, NULL, NULL, META_DT_NONE, true }
+    static const fwk::MetaDataFormat s_shootinginfo_format[] = {
+        { _("Exposure Program:"), eng::NpExifExposureProgramProp, fwk::META_DT_STRING, true },
+        { _("Speed:"), eng::NpExifExposureTimeProp, fwk::META_DT_STRING, true },
+        { _("Aperture:"), eng::NpExifFNumberPropProp, fwk::META_DT_FRAC, true },
+        { _("ISO:"), eng::NpExifIsoSpeedRatingsProp, fwk::META_DT_STRING_ARRAY, true },
+        { _("Exposure Bias:"), eng::NpExifExposureBiasProp, fwk::META_DT_FRAC, true },
+        { _("Flash:"), eng::NpExifFlashFiredProp, fwk::META_DT_STRING, true },
+        { _("Flash compensation:"), eng::NpExifAuxFlashCompensationProp, fwk::META_DT_STRING, true },
+        { _("Focal length:"), eng::NpExifFocalLengthProp, fwk::META_DT_FRAC, true },
+        { _("White balance:"), eng::NpExifWbProp, fwk::META_DT_STRING, true },
+        { _("Date:"), eng::NpExifDateTimeOriginalProp, fwk::META_DT_DATE, false },
+        { NULL, 0, fwk::META_DT_NONE, true }
     };
-    static const MetaDataFormat s_iptc_format[] = {
-      { _("Rating:"), NS_XAP, "Rating", META_DT_STAR_RATING, false },
-      { _("Label:"), NS_XAP, "Label", META_DT_STRING, false },            
-      { _("Keywords:"), NS_DC, "subject", META_DT_STRING_ARRAY, false },
-      { NULL, NULL, NULL, META_DT_NONE, true }			
+    static const fwk::MetaDataFormat s_iptc_format[] = {
+        { _("Headline:"), eng::NpIptcHeadlineProp, fwk::META_DT_STRING, false },
+        { _("Caption:"), eng::NpIptcDescriptionProp, fwk::META_DT_TEXT, false },
+        { _("Rating:"), eng::NpXmpRatingProp, fwk::META_DT_STAR_RATING, false },
+        { _("Label:"), eng::NpXmpLabelProp, fwk::META_DT_STRING, false },            
+        { _("Keywords:"), eng::NpIptcKeywordsProp, fwk::META_DT_STRING_ARRAY, false },
+        { NULL, 0, fwk::META_DT_NONE, true }			
     };
-    static const MetaDataSectionFormat s_format[] = {
-      { _("Camera Information"),
-	s_camerainfo_format
-      },
-      { _("Shooting Information"),
-	s_shootinginfo_format
-      },
-      { _("IPTC"),
-	s_iptc_format
-      },
-      { _("Rights"),
-	NULL
-      },
-      { NULL, NULL
-      }
+    static const fwk::MetaDataSectionFormat s_format[] = {
+        { _("Camera Information"),
+          s_camerainfo_format
+        },
+        { _("Shooting Information"),
+          s_shootinginfo_format
+        },
+        { _("IPTC"),
+          s_iptc_format
+        },
+        { _("Rights"),
+          NULL
+        },
+        { NULL, NULL
+        }
     };
     return s_format;
-  }
+}
+
+const fwk::PropertySet & MetaDataPaneController::get_property_set()
+{
+    static fwk::PropertySet propset;
+    if(propset.empty()) {
+        const fwk::MetaDataSectionFormat * formats = get_format();
+        
+        const fwk::MetaDataSectionFormat * current = formats;
+        while(current->section) {
+            const fwk::MetaDataFormat * format = current->formats;
+            while(format && format->label) {
+                propset.insert(format->id);
+                format++;
+            }
+            current++;
+        }
+    }
+    return propset;
+}
+
   
-  MetaDataPaneController::MetaDataPaneController()
+MetaDataPaneController::MetaDataPaneController()
     : Dockable("Metadata", _("Image Properties"), 
 	       Gtk::Stock::PROPERTIES.id /*, DockItem::DOCKED_STATE*/),
       m_fileid(0)
-  {
-  }
-  
-  MetaDataPaneController::~MetaDataPaneController()
-  {
-  }
-  
-  Gtk::Widget * 
-  MetaDataPaneController::buildWidget(const Glib::RefPtr<Gtk::UIManager> & )
-  {
+{
+}
+
+MetaDataPaneController::~MetaDataPaneController()
+{
+}
+
+Gtk::Widget * 
+MetaDataPaneController::buildWidget(const Glib::RefPtr<Gtk::UIManager> & )
+{
     if(m_widget) {
-      return m_widget;
+        return m_widget;
     }
     Gtk::VBox *vbox = build_vbox();
     m_widget = vbox;
     DBG_ASSERT(vbox, "dockable vbox not found");
-
-    const MetaDataSectionFormat * formats = get_format();
     
-    const MetaDataSectionFormat * current = formats;
+    const fwk::MetaDataSectionFormat * formats = get_format();
+    
+    const fwk::MetaDataSectionFormat * current = formats;
     while(current->section) {
-      fwk::MetaDataWidget *w = Gtk::manage(new fwk::MetaDataWidget(current->section));
-      vbox->pack_start(*w, Gtk::PACK_SHRINK, 0);
-      w->set_data_format(current);
-      m_widgets.push_back(w);
-      current++;
+        fwk::MetaDataWidget *w = Gtk::manage(new fwk::MetaDataWidget(current->section));
+        vbox->pack_start(*w, Gtk::PACK_SHRINK, 0);
+        w->set_data_format(current);
+        m_widgets.push_back(w);
+        w->signal_metadata_changed.connect(
+            sigc::mem_fun(*this, 
+                          &MetaDataPaneController::on_metadata_changed));
+        current++;
     }
     
     return m_widget;
-  }
-  
+}
   
-	void MetaDataPaneController::display(eng::library_id_t file_id, const fwk::XmpMeta * meta)
-  {
+void MetaDataPaneController::on_metadata_changed(const fwk::PropertyBag & props)
+{
+    signal_metadata_changed.emit(props);
+}
+
+
+void MetaDataPaneController::display(eng::library_id_t file_id, const fwk::XmpMeta * meta)
+{
     m_fileid = file_id;
     DBG_OUT("displaying metadata");
+    fwk::PropertyBag properties;
+    if(meta) {
+        const fwk::PropertySet & propset = get_property_set();
+        eng::convert_xmp_to_properties(meta, propset, properties);
+    }
     std::for_each(m_widgets.begin(), m_widgets.end(),
 		  boost::bind(&fwk::MetaDataWidget::set_data_source,
-			      _1, meta));
-  }
+			      _1, properties));
+}
   
 }
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0))
+  indent-tabs-mode:nil
+  fill-column:80
+  End:
+*/
diff --git a/src/niepce/ui/metadatapanecontroller.hpp b/src/niepce/ui/metadatapanecontroller.hpp
index bdc539b..8f20291 100644
--- a/src/niepce/ui/metadatapanecontroller.hpp
+++ b/src/niepce/ui/metadatapanecontroller.hpp
@@ -26,12 +26,11 @@
 #include "fwk/utils/exempi.hpp"
 #include "fwk/toolkit/dockable.hpp"
 
-namespace xmp {
-struct MetaDataSectionFormat;
-}
 namespace fwk {
+struct MetaDataSectionFormat;
 class MetaDataWidget;
 class Dock;
+class PropertyBag;
 }
 
 namespace ui {
@@ -47,12 +46,17 @@ public:
     void display(eng::library_id_t file_id, const fwk::XmpMeta * meta);
     eng::library_id_t displayed_file() const 
         { return m_fileid; }
+
+    sigc::signal<void, const fwk::PropertyBag &> signal_metadata_changed;
 private:
+    void on_metadata_changed(const fwk::PropertyBag &);
+
     std::vector<fwk::MetaDataWidget *> m_widgets;
     
-    static const xmp::MetaDataSectionFormat * get_format();
+    static const fwk::MetaDataSectionFormat * get_format();
+    static const fwk::PropertySet & get_property_set();
     
-	eng::library_id_t m_fileid;
+    eng::library_id_t m_fileid;
 };
 
 }
diff --git a/src/niepce/ui/selectioncontroller.cpp b/src/niepce/ui/selectioncontroller.cpp
index 38fd780..0282194 100644
--- a/src/niepce/ui/selectioncontroller.cpp
+++ b/src/niepce/ui/selectioncontroller.cpp
@@ -243,13 +243,37 @@ void SelectionController::set_flag(int flag)
             _set_metadata(_("Set Flag"), file, 
                           MAKE_METADATA_IDX(eng::META_NS_NIEPCE, eng::META_NIEPCE_FLAG), 
                           old_value, flag);
+            // we need to set the flag here so that undo/redo works
+            // consistently.
+            file->setFlag(flag);
+        }
+    }
+}
+
+
+void SelectionController::set_properties(const fwk::PropertyBag & /*props*/)
+{
+    eng::library_id_t selection = get_selection();
+    if(selection >= 0) {
+        Gtk::TreeIter iter = m_imageliststore->get_iter_from_id(selection);
+        if(iter) {
+#if 0
+            eng::LibFile::Ptr file = (*iter)[m_imageliststore->columns().m_libfile];
+            DBG_OUT("old flag is %d", file->flag());
+            int old_value = file->flag();
+            _set_metadata(_("Set Properties"), file, 
+                          // FIXME
+                          MAKE_METADATA_IDX(eng::META_NS_XMPCORE, eng::META_XMPCORE_RATING),
+                          old_value, flag);
             // we need to set the rating here so that undo/redo works
             // consistently.
             file->setFlag(flag);
+#endif
         }
     }
 }
 
+
 }
 
 /*
diff --git a/src/niepce/ui/selectioncontroller.hpp b/src/niepce/ui/selectioncontroller.hpp
index bbaeb25..cf04770 100644
--- a/src/niepce/ui/selectioncontroller.hpp
+++ b/src/niepce/ui/selectioncontroller.hpp
@@ -25,6 +25,7 @@
 
 #include <sigc++/signal.h>
 
+#include "fwk/base/propertybag.hpp"
 #include "fwk/toolkit/controller.hpp"
 #include "engine/db/librarytypes.hpp";
 #include "ui/imageliststore.hpp"
@@ -90,6 +91,8 @@ public:
     /** set flag */
     void set_flag(int flag);
 
+    void set_properties(const fwk::PropertyBag & props);
+
     /** get the current selection 
      *  todo: change it to support multiple
      */



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