xmpedit

GTK+ editor for XMP metadata embedded in images
git clone https://code.djc.id.au/git/xmpedit/
commit 6eca2505bd61692d12c50c2ded3cc1744e45b6dd
parent f35198931212cd008d4dd2ce7c426cab99a67e0d
Author: Dan Callaghan <djc@djc.id.au>
Date:   Sat, 17 Jul 2010 10:07:31 +1000

attempt at tying together property list and editor frame (does NOT work, but committed anyway in preparation for switching to vala)

Diffstat:
MMainWindow.cpp | 42++++++++++++++++++++++++++++++++----------
MMainWindow.h | 13++++++++++---
MMetadataTreeModel.cpp | 25++++++++-----------------
MMetadataTreeModel.h | 10++++++----
MMetadataTreeView.cpp | 3+++
APropertyEditor.cpp | 30++++++++++++++++++++++++++++++
APropertyEditor.h | 21+++++++++++++++++++++
MSConstruct | 1+
8 files changed, 111 insertions(+), 34 deletions(-)
diff --git a/MainWindow.cpp b/MainWindow.cpp
@@ -1,25 +1,47 @@
 
 #include <giomm/file.h>
+#include <exiv2/convert.hpp>
 #include "MainWindow.h"
 
 MainWindow::MainWindow(const std::string& path) :
+	image(Exiv2::ImageFactory::open(path)),
+	table(/* rows */ 2, /* cols */ 2),
     image_preview(Gdk::Pixbuf::create_from_file(path, 320, 320)),
-    model(MetadataTreeModel::create(path)),
+    model(MetadataTreeModel::create(property_editors)),
     tree_view(model) {
 
+    image->readMetadata();
+    Exiv2::XmpData data = image->xmpData();
+    for (Exiv2::XmpData::iterator i = data.begin(); i != data.end(); ++ i) {
+        property_editors.push_back(PropertyEditor::create(*i));
+    }
+
     {
         Glib::RefPtr<Gio::File> file(Gio::File::create_for_path(path));
         set_title(file->get_basename());
     }
-
-    add(vbox);
-
-    vbox.pack_start(image_preview, Gtk::PACK_SHRINK, 10);
-
-    scrolled.add(tree_view);
-    scrolled.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
-    vbox.pack_start(scrolled, Gtk::PACK_EXPAND_WIDGET);
-
+    set_default_size(640, 480);
+    property_allow_shrink() = true;
+
+    table.attach(image_preview,
+    		1, 2, 0, 1,
+    		Gtk::FILL | Gtk::EXPAND, Gtk::FILL,
+    		10, 10);
+
+    tree_view_scrolled.add(tree_view);
+    tree_view_scrolled.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+    table.attach(tree_view_scrolled,
+    		0, 1, 0, 2,
+    		Gtk::FILL, Gtk::FILL | Gtk::EXPAND,
+    		0, 0);
+
+    detail_scrolled.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
+    table.attach(detail_scrolled,
+    		1, 2, 1, 2,
+    		Gtk::FILL | Gtk::EXPAND, Gtk::FILL | Gtk::EXPAND,
+    		0, 0);
+
+    add(table);
     show_all_children();
 
 }
diff --git a/MainWindow.h b/MainWindow.h
@@ -2,11 +2,15 @@
 #ifndef MAINWINDOW_H_
 #define MAINWINDOW_H_
 
+#include <vector>
+#include <exiv2/image.hpp>
+#include "PropertyEditor.h"
 #include "MetadataTreeModel.h"
 #include "MetadataTreeView.h"
 #include <gtkmm/treeview.h>
 #include <gtkmm/scrolledwindow.h>
-#include <gtkmm/box.h>
+#include <gtkmm/table.h>
+#include <gtkmm/alignment.h>
 #include <gtkmm/window.h>
 
 class MainWindow : public Gtk::Window {
@@ -16,11 +20,14 @@ public:
     virtual ~MainWindow();
 
 private:
-    Gtk::VBox vbox;
+    Exiv2::Image::AutoPtr image;
+    std::vector<boost::shared_ptr<PropertyEditor> > property_editors;
+    Gtk::Table table;
     Gtk::Image image_preview;
-    Gtk::ScrolledWindow scrolled;
+    Gtk::ScrolledWindow tree_view_scrolled;
     Glib::RefPtr<MetadataTreeModel> model;
     MetadataTreeView tree_view;
+    Gtk::ScrolledWindow detail_scrolled;
 
 };
 
diff --git a/MetadataTreeModel.cpp b/MetadataTreeModel.cpp
@@ -1,29 +1,20 @@
 
 #include "MetadataTreeModel.h"
-#include <exiv2/convert.hpp>
 
-MetadataTreeModel::MetadataTreeModel(const std::string& path) {
+MetadataTreeModel::MetadataTreeModel(const std::vector<boost::shared_ptr<PropertyEditor> >& property_editors) {
     set_column_types(columns);
 
-    Exiv2::Image::AutoPtr image(Exiv2::ImageFactory::open(path));
-    image->readMetadata();
-    Exiv2::XmpData data = image->xmpData();
-
-    for (Exiv2::XmpData::const_iterator i = data.begin(); i != data.end(); ++ i) {
-        Row row(*append());
-        Glib::ustring markup("<b>Unknown property (");
-        markup += i->groupName();
-        markup += ":";
-        markup += i->tagName();
-        markup += ")</b>\n";
-        markup += i->value().toString(); // XXX escape
-        row[columns.markup_column] = markup;
+    for (std::vector<boost::shared_ptr<PropertyEditor> >::const_iterator i = property_editors.begin();
+    		i != property_editors.end(); ++ i) {
+    	Row row(*append());
+        row[columns.markup_column] = (*i)->get_list_markup();
     }
 }
 
 MetadataTreeModel::~MetadataTreeModel(void) {
 }
 
-Glib::RefPtr<MetadataTreeModel> MetadataTreeModel::create(const std::string& path) {
-    return Glib::RefPtr<MetadataTreeModel>(new MetadataTreeModel(path));
+Glib::RefPtr<MetadataTreeModel> MetadataTreeModel::create(
+		const std::vector<boost::shared_ptr<PropertyEditor> >& property_editors) {
+    return Glib::RefPtr<MetadataTreeModel>(new MetadataTreeModel(property_editors));
 }
diff --git a/MetadataTreeModel.h b/MetadataTreeModel.h
@@ -2,16 +2,18 @@
 #ifndef METADATATREEMODEL_H_
 #define METADATATREEMODEL_H_
 
-#include <string>
+#include <vector>
 #include <gtkmm/liststore.h>
-#include <exiv2/image.hpp>
+#include "PropertyEditor.h"
 
 class MetadataTreeModel : public Gtk::ListStore {
 
+private:
+	MetadataTreeModel(const std::vector<boost::shared_ptr<PropertyEditor> >& property_editors);
+
 public:
-    MetadataTreeModel(const std::string& path);
     virtual ~MetadataTreeModel(void);
-    static Glib::RefPtr<MetadataTreeModel> create(const std::string& path);
+    static Glib::RefPtr<MetadataTreeModel> create(const std::vector<boost::shared_ptr<PropertyEditor> >& property_editors);
 
 private:
     struct ModelColumns : public Gtk::TreeModel::ColumnRecord {
diff --git a/MetadataTreeView.cpp b/MetadataTreeView.cpp
@@ -4,6 +4,9 @@
 MetadataTreeView::MetadataTreeView(Glib::RefPtr<MetadataTreeModel> model) :
 	column("Image properties") {
 	set_model(model);
+	cell_renderer.property_ellipsize() = Pango::ELLIPSIZE_END;
+	column.set_sizing(Gtk::TREE_VIEW_COLUMN_FIXED);
+	column.set_fixed_width(300);
 	column.pack_start(cell_renderer, true);
 	column.add_attribute(cell_renderer.property_markup(), model->columns.markup_column);
 	append_column(column);
diff --git a/PropertyEditor.cpp b/PropertyEditor.cpp
@@ -0,0 +1,30 @@
+
+#include "PropertyEditor.h"
+
+class UnrecognisedPropertyEditor : public PropertyEditor {
+
+private:
+	Exiv2::Xmpdatum& xmp_property;
+
+public:
+	UnrecognisedPropertyEditor(Exiv2::Xmpdatum& xmp_property) :
+		xmp_property(xmp_property) {
+	}
+
+	virtual ~UnrecognisedPropertyEditor(void) {
+	}
+
+	virtual Glib::ustring get_list_markup(void) const {
+        Glib::ustring markup("<b>Unknown property (");
+        markup += xmp_property.groupName();
+        markup += ":";
+        markup += xmp_property.tagName();
+        markup += ")</b>\n";
+        markup += xmp_property.value().toString(); // XXX escape
+        return markup;
+	}
+};
+
+boost::shared_ptr<PropertyEditor> PropertyEditor::create(Exiv2::Xmpdatum& xmp_property) {
+	return boost::shared_ptr<PropertyEditor>(new UnrecognisedPropertyEditor(xmp_property));
+}
diff --git a/PropertyEditor.h b/PropertyEditor.h
@@ -0,0 +1,21 @@
+
+#ifndef PROPERTYEDITOR_H_
+#define PROPERTYEDITOR_H_
+
+#include <boost/shared_ptr.hpp>
+#include <glibmm/ustring.h>
+#include <exiv2/xmp.hpp>
+
+class PropertyEditor {
+
+public:
+    virtual ~PropertyEditor(void) {
+    }
+
+    virtual Glib::ustring get_list_markup(void) const = 0;
+
+    static boost::shared_ptr<PropertyEditor> create(Exiv2::Xmpdatum& xmp_property);
+
+};
+
+#endif /* PROPERTYEDITOR_H_ */
diff --git a/SConstruct b/SConstruct
@@ -2,6 +2,7 @@
 import os
 env = Environment(CFLAGS=os.environ.get('CFLAGS', '').split() + ['-Wall', '-ggdb'])
 env['CXXFLAGS'] = env['CFLAGS']
+env.ParseFlags('-I/usr/include/boost-1_42 -L/usr/lib/boost-1_42') # XXX
 env.ParseConfig('pkg-config --cflags --libs gtkmm-2.4')
 env.ParseConfig('pkg-config --cflags --libs giomm-2.4')
 env.ParseConfig('pkg-config --cflags --libs exiv2')