Fix ExportFormatSpecification copy-c'tor
[ardour.git] / gtk2_ardour / session_metadata_dialog.cc
index 35920038bed0debb5bfe512b02ed4f08b8b051ba..ce8d76c57eebe79baee0247457446c57b81a0f55 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2008 Paul Davis 
+    Copyright (C) 2008 Paul Davis
     Author: Sakari Bergen
 
     This program is free software; you can redistribute it and/or modify it
     675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include "session_metadata_dialog.h"
-
 #include <sstream>
+#include <gtkmm/filechooserdialog.h>
+#include <gtkmm/messagedialog.h>
+#include <gtkmm/stock.h>
+
+#include "pbd/xml++.h"
+#include "pbd/error.h"
+
+#include "ardour/filename_extensions.h"
+#include "ardour/session.h"
+#include "ardour/session_utils.h"
+
+#include "gtkmm2ext/utils.h"
+
+#include "session_metadata_dialog.h"
 
-#include <gtkmm2ext/utils.h>
-#include <gtkmm2ext/window_title.h>
+#include "pbd/i18n.h"
 
-#include "i18n.h"
-#include <pbd/xml++.h>
-#include <ardour/session.h>
-#include <ardour/session_directory.h>
-#include <ardour/session_utils.h>
+using namespace std;
+using namespace Glib;
+using namespace PBD;
 
 #define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
 
 /*** MetadataField ***/
 
-MetadataField::MetadataField (ustring const & field_name) :
+MetadataField::MetadataField (string const & field_name) :
   _name (field_name)
 {
 }
@@ -43,7 +52,7 @@ MetadataField::~MetadataField() { }
 
 /* TextMetadataField */
 
-TextMetadataField::TextMetadataField (Getter getter, Setter setter, ustring const & field_name, guint width ) :
+TextMetadataField::TextMetadataField (Getter getter, Setter setter, string const & field_name, guint width ) :
   MetadataField (field_name),
   getter (getter),
   setter (setter),
@@ -78,7 +87,8 @@ TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
 Gtk::Widget &
 TextMetadataField::name_widget ()
 {
-       label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
+       label = Gtk::manage (new Gtk::Label(_name + ':'));
+       label->set_alignment (1, 0);
        return *label;
 }
 
@@ -93,11 +103,11 @@ Gtk::Widget &
 TextMetadataField::edit_widget ()
 {
        entry = Gtk::manage (new Gtk::Entry());
-       
+
        entry->set_text (_value);
        entry->set_width_chars (width);
        entry->signal_changed().connect (sigc::mem_fun(*this, &TextMetadataField::update_value));
-       
+
        return *entry;
 }
 
@@ -107,9 +117,47 @@ TextMetadataField::update_value ()
        _value = entry->get_text ();
 }
 
+/* LongTextMetadataField */
+
+LongTextMetadataField::LongTextMetadataField (Getter getter, Setter setter, string const & field_name, guint width ) :
+  TextMetadataField (getter, setter, field_name, width)
+{
+       tview = 0;
+       label = 0;
+       value_label = 0;
+}
+
+MetadataPtr
+LongTextMetadataField::copy ()
+{
+       return MetadataPtr (new TextMetadataField (getter, setter, _name, width));
+}
+
+Gtk::Widget &
+LongTextMetadataField::edit_widget ()
+{
+       tview = Gtk::manage (new Gtk::TextView());
+
+       tview->get_buffer()->set_text (_value);
+       tview->set_wrap_mode (Gtk::WRAP_WORD);
+       tview->set_size_request (-1, 400);
+       tview->set_editable (true);
+
+       Glib::RefPtr<Gtk::TextBuffer> tb (tview->get_buffer());
+       tb->signal_changed().connect (sigc::mem_fun(*this, &LongTextMetadataField::update_value));
+
+       return *tview;
+}
+
+void
+LongTextMetadataField::update_value ()
+{
+       _value = tview->get_buffer()->get_text ();
+}
+
 /* NumberMetadataField */
 
-NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, ustring const & field_name, guint numbers, guint width) :
+NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, string const & field_name, guint numbers, guint width) :
   MetadataField (field_name),
   getter (getter),
   setter (setter),
@@ -147,7 +195,7 @@ NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data)
 void
 NumberMetadataField::update_value ()
 {
-       // Accpt only numbers
+       // Accept only numbers that will fit into a uint32_t
        uint32_t number = str_to_uint (entry->get_text());
        _value = uint_to_str (number);
        entry->set_text (_value);
@@ -156,7 +204,8 @@ NumberMetadataField::update_value ()
 Gtk::Widget &
 NumberMetadataField::name_widget ()
 {
-       label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
+       label = Gtk::manage (new Gtk::Label(_name + ':'));
+       label->set_alignment (1, 0);
        return *label;
 }
 
@@ -171,16 +220,16 @@ Gtk::Widget &
 NumberMetadataField::edit_widget ()
 {
        entry = Gtk::manage (new Gtk::Entry());
-       
+
        entry->set_text (_value);
        entry->set_width_chars (width);
        entry->set_max_length (numbers);
        entry->signal_changed().connect (sigc::mem_fun(*this, &NumberMetadataField::update_value));
-       
+
        return *entry;
 }
 
-ustring
+string
 NumberMetadataField::uint_to_str (uint32_t i) const
 {
        std::ostringstream oss ("");
@@ -193,14 +242,14 @@ NumberMetadataField::uint_to_str (uint32_t i) const
 }
 
 uint32_t
-NumberMetadataField::str_to_uint (ustring const & str) const
+NumberMetadataField::str_to_uint (string const & str) const
 {
-       ustring tmp (str);
-       ustring::size_type i;
-       while ((i = tmp.find_first_not_of("1234567890")) != ustring::npos) {
+       string tmp (str);
+       string::size_type i;
+       while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
                tmp.erase (i, 1);
        }
-       
+
        std::istringstream iss(tmp);
        uint32_t result = 0;
        iss >> result;
@@ -208,12 +257,134 @@ NumberMetadataField::str_to_uint (ustring const & str) const
 }
 
 
+
+/* EAN13MetadataField */
+
+EAN13MetadataField::EAN13MetadataField (Getter getter, Setter setter, string const & field_name, guint width) :
+  MetadataField (field_name),
+  getter (getter),
+  setter (setter),
+  width (width)
+{
+       entry = 0;
+       label = 0;
+       value_label = 0;
+       status_label = Gtk::manage (new Gtk::Label (""));
+}
+
+MetadataPtr
+EAN13MetadataField::copy ()
+{
+       return MetadataPtr (new EAN13MetadataField (getter, setter, _name, width));
+}
+
+void
+EAN13MetadataField::save_data (ARDOUR::SessionMetadata & data) const
+{
+       CALL_MEMBER_FN (data, setter) (_value);
+}
+
+void
+EAN13MetadataField::load_data (ARDOUR::SessionMetadata const & data)
+{
+       _value = CALL_MEMBER_FN (data, getter) ();
+       if (entry) {
+               entry->set_text (_value);
+       }
+       update_status ();
+}
+
+void
+EAN13MetadataField::update_value ()
+{
+       // Accept only numeric characters
+       _value = numeric_string (entry->get_text());
+       entry->set_text (_value);
+       update_status ();
+}
+
+void
+EAN13MetadataField::update_status ()
+{
+       int len = _value.length ();
+       if (len == 13) {
+               // calculate EAN-13 modulo 10 check digit
+               int sum = 0;
+               const char *p = _value.c_str();
+               for (int i = 0; i < 12; i++) {
+                       char c = p[i] - '0';
+                       if (i % 2) {
+                               sum += c * 3;
+                       } else {
+                               sum += c;
+                       }
+               }
+               sum %= 10;
+               if (sum)
+                       sum = 10 - sum;
+
+               if (sum == p[12] - '0') {
+                       status_label->set_markup (string_compose(
+                                               "<span color=\"green\">%1: %2</span>",
+                                               _("EAN Check digit OK"), sum));
+               } else {
+                       status_label->set_markup (string_compose(
+                                               "<span color=\"#ffa755\">%1: %2 (%3 %4)</span>",
+                                               _("EAN Check digit error"), p[12] - '0', _("expected"), sum));
+               }
+       } else if (len > 0) {
+               status_label->set_markup (string_compose(
+                                       "<span color=\"#ffa755\">%1: %2 (&lt;13)</span>",
+                                       _("EAN Length error"), len));
+       } else {
+               status_label->set_text("");
+       }
+}
+
+Gtk::Widget &
+EAN13MetadataField::name_widget ()
+{
+       label = Gtk::manage (new Gtk::Label(_name + ':'));
+       label->set_alignment (1, 0);
+       return *label;
+}
+
+Gtk::Widget &
+EAN13MetadataField::value_widget ()
+{
+       value_label = Gtk::manage (new Gtk::Label(_value));
+       return *value_label;
+}
+
+Gtk::Widget &
+EAN13MetadataField::edit_widget ()
+{
+       entry = Gtk::manage (new Gtk::Entry());
+
+       entry->set_text (_value);
+       entry->set_width_chars (width);
+       entry->set_max_length (13);
+       entry->signal_changed().connect (sigc::mem_fun(*this, &EAN13MetadataField::update_value));
+
+       return *entry;
+}
+
+string
+EAN13MetadataField::numeric_string (string const & str) const
+{
+       string tmp (str);
+       string::size_type i;
+       while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
+               tmp.erase (i, 1);
+       }
+       return tmp;
+}
+
 /* SessionMetadataSet */
 
-SessionMetadataSet::SessionMetadataSet (ustring const & name) :
-  name (name)
+SessionMetadataSet::SessionMetadataSet (string const & name)
+  name (name)
 {
-       session = 0;
 }
 
 void
@@ -224,11 +395,15 @@ SessionMetadataSet::add_data_field (MetadataPtr field)
 
 /* SessionMetadataSetEditable */
 
-SessionMetadataSetEditable::SessionMetadataSetEditable (ustring const & name) :
-  SessionMetadataSet (name)
+SessionMetadataSetEditable::SessionMetadataSetEditable (string const & name)
+  SessionMetadataSet (name)
 {
        table.set_row_spacings (6);
        table.set_col_spacings (12);
+       table.set_homogeneous (false);
+       vbox.pack_start (table, false, false);
+       vbox.set_spacing (6);
+       vbox.set_border_width (6);
 }
 
 Gtk::Widget &
@@ -241,17 +416,21 @@ SessionMetadataSetEditable::get_tab_widget ()
 void
 SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
 {
-       session = s;
-       
-       ARDOUR::SessionMetadata const & data = session->metadata();
-       
+       SessionHandlePtr::set_session (s);
+
+       if (!_session) {
+               return;
+       }
+
+       ARDOUR::SessionMetadata const & data = *(ARDOUR::SessionMetadata::Metadata());
+
        table.resize (list.size(), 2);
        uint32_t row = 0;
        MetadataPtr field;
        for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
                field = *it;
                field->load_data (data);
-               table.attach (field->name_widget(), 0, 1, row, row + 1);
+               table.attach (field->name_widget(), 0, 1, row, row + 1, Gtk::FILL);
                table.attach (field->edit_widget(), 1, 2, row, row + 1);
                ++row;
        }
@@ -260,7 +439,7 @@ SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
 void
 SessionMetadataSetEditable::save_data ()
 {
-       ARDOUR::SessionMetadata & data = session->metadata();
+       ARDOUR::SessionMetadata & data = *(ARDOUR::SessionMetadata::Metadata());
        for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
                (*it)->save_data(data);
        }
@@ -268,34 +447,32 @@ SessionMetadataSetEditable::save_data ()
 
 /* SessionMetadataSetImportable */
 
-SessionMetadataSetImportable::SessionMetadataSetImportable (ustring const & name) :
-  SessionMetadataSet (name),
-  session_list (list)
+SessionMetadataSetImportable::SessionMetadataSetImportable (string const & name)
+  : SessionMetadataSet (name)
+  session_list (list)
 {
        tree = Gtk::ListStore::create (tree_cols);
        tree_view.set_model (tree);
-       
+
        Gtk::TreeView::Column * viewcol;
-       
+
        // Add import column
        Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle());
        import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed));
        viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render));
        viewcol->add_attribute (import_render->property_active(), tree_cols.import);
        tree_view.append_column (*viewcol);
-       
+
        // Add field name column
        tree_view.append_column(_("Field"), tree_cols.field);
-       
+
        // Add values column with pango markup
        Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText());
        viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render));
        viewcol->add_attribute (values_render->property_markup(), tree_cols.values);
        tree_view.append_column (*viewcol);
-       
+
        select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all));
-       
-       session = 0;
 }
 
 Gtk::Widget &
@@ -315,18 +492,18 @@ SessionMetadataSetImportable::get_select_all_widget ()
 void
 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data)
 {
-       if (!session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl;
+       if (!_session) {
+               error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataSetImportable (in load_data)!") << endmsg;
                return;
        }
-       
-       ARDOUR::SessionMetadata & session_data = session->metadata();
-       
+
+       ARDOUR::SessionMetadata const & session_data = *(ARDOUR::SessionMetadata::Metadata());
+
        MetadataPtr session_field;
        MetadataPtr import_field;
        DataList::iterator session_it;
        DataList::iterator import_it;
-       
+
        // Copy list and load data to import
        for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) {
                session_field = *session_it;
@@ -340,13 +517,13 @@ SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & d
        while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same...
                session_field = *session_it;
                import_field = *import_it;
-               
+
                import_field->load_data(data); // hasn't been done yet
-               
+
                // Make string for values TODO get color from somewhere?
-               ustring values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
-                               + "<span weight=\"bold\">" + import_field->value() + "</span>";
-               
+               string values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
+                        + "<span weight=\"bold\">" + import_field->value() + "</span>";
+
                Gtk::TreeModel::iterator row_iter = tree->append();
                Gtk::TreeModel::Row row = *row_iter;
 
@@ -354,7 +531,7 @@ SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & d
                row[tree_cols.values] = values;
                row[tree_cols.import] = false;
                row[tree_cols.data] = import_field;
-               
+
                ++session_it;
                ++import_it;
        }
@@ -363,12 +540,12 @@ SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & d
 void
 SessionMetadataSetImportable::save_data ()
 {
-       if (!session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl;
+       if (!_session) {
+               error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataSetImportable (in import_data)!") << endmsg;
                return;
        }
 
-       ARDOUR::SessionMetadata & session_data = session->metadata();
+       ARDOUR::SessionMetadata & session_data = *(ARDOUR::SessionMetadata::Metadata());
 
        Gtk::TreeModel::Children fields = tree->children();
        Gtk::TreeModel::Children::iterator it;
@@ -385,7 +562,7 @@ SessionMetadataSetImportable::select_all ()
 {
        select_all_check.set_inconsistent (false);
        bool state = select_all_check.get_active();
-       
+
        Gtk::TreeModel::Children fields = tree->children();
        Gtk::TreeModel::Children::iterator it;
        for (it = fields.begin(); it != fields.end(); ++it) {
@@ -394,10 +571,10 @@ SessionMetadataSetImportable::select_all ()
 }
 
 void
-SessionMetadataSetImportable::selection_changed (ustring const & path)
+SessionMetadataSetImportable::selection_changed (string const & path)
 {
        select_all_check.set_inconsistent (true);
-       
+
        Gtk::TreeModel::iterator iter = tree->get_iter (path);
        bool value((*iter)[tree_cols.import]);
        (*iter)[tree_cols.import] = !value;
@@ -406,31 +583,35 @@ SessionMetadataSetImportable::selection_changed (ustring const & path)
 /* SessionMetadataDialog */
 
 template <typename DataSet>
-SessionMetadataDialog<DataSet>::SessionMetadataDialog (ustring const & name) :
+SessionMetadataDialog<DataSet>::SessionMetadataDialog (string const & name) :
   ArdourDialog (name, true)
 {
        cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
-       cancel_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::end_dialog));
-       save_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
-       save_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::save_and_close));
+       cancel_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::end_dialog));
+       save_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
+       save_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::save_and_close));
 }
 
 template <typename DataSet>
 void
-SessionMetadataDialog<DataSet>::init_data ()
+SessionMetadataDialog<DataSet>::init_data ( bool skip_user )
 {
-       if (!session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl;
+       if (!_session) {
+               error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataDialog (in init_data)!") << endmsg;
                return;
        }
-       
+
+       if (!skip_user)
+               init_user_data ();
        init_track_data ();
        init_album_data ();
        init_people_data ();
-       
+       init_school_data ();
+       init_description_data ();
+
        for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
-               (*it)->set_session (session);
-               
+               (*it)->set_session (_session);
+
                notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget());
        }
 }
@@ -458,6 +639,7 @@ void
 SessionMetadataDialog<DataSet>::save_and_close ()
 {
        save_data ();
+       _session->set_dirty();
        end_dialog ();
 }
 
@@ -470,7 +652,7 @@ SessionMetadataDialog<DataSet>::end_dialog ()
 
 template <typename DataSet>
 void
-SessionMetadataDialog<DataSet>::warn_user (ustring const & string)
+SessionMetadataDialog<DataSet>::warn_user (string const & string)
 {
        Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
        msg.run();
@@ -486,7 +668,7 @@ SessionMetadataDialog<DataSet>::get_custom_widgets (WidgetFunc f)
                DataSet * set = dynamic_cast<DataSet *> (it->get());
                list->push_back (& CALL_MEMBER_FN (*set, f) ());
        }
-       
+
        return list;
 }
 
@@ -497,6 +679,46 @@ SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
        get_vbox()->pack_start (widget, true, true, 0);
 }
 
+template <typename DataSet>
+void
+SessionMetadataDialog<DataSet>::init_user_data ()
+{
+       DataSetPtr data_set (new DataSet (_("User")));
+       data_list.push_back (data_set);
+
+       MetadataPtr ptr;
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_name, &ARDOUR::SessionMetadata::set_user_name, _("Name")));
+       data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_email, &ARDOUR::SessionMetadata::set_user_email, _("Email")));
+       data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_web, &ARDOUR::SessionMetadata::set_user_web, _("Web")));
+       data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::organization, &ARDOUR::SessionMetadata::set_organization, _("Organization")));
+       data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::country, &ARDOUR::SessionMetadata::set_country, _("Country")));
+       data_set->add_data_field (ptr);
+
+}
+
+template <typename DataSet>
+void
+SessionMetadataDialog<DataSet>::init_description_data ()
+{
+       DataSetPtr data_set (new DataSet (_("Description")));
+       data_list.push_back (data_set);
+
+       MetadataPtr ptr;
+
+       ptr = MetadataPtr (new LongTextMetadataField (&ARDOUR::SessionMetadata::description, &ARDOUR::SessionMetadata::set_description, _("Description")));
+       data_set->add_data_field (ptr);
+}
+
+
 template <typename DataSet>
 void
 SessionMetadataDialog<DataSet>::init_track_data ()
@@ -505,28 +727,28 @@ SessionMetadataDialog<DataSet>::init_track_data ()
        data_list.push_back (data_set);
 
        MetadataPtr ptr;
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright")));
        data_set->add_data_field (ptr);
 }
@@ -537,35 +759,43 @@ SessionMetadataDialog<DataSet>::init_album_data ()
 {
        DataSetPtr data_set (new DataSet (_("Album")));
        data_list.push_back (data_set);
-       
+
        MetadataPtr ptr;
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC")));
        data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new EAN13MetadataField (&ARDOUR::SessionMetadata::barcode, &ARDOUR::SessionMetadata::set_barcode, _("EAN barcode")));
+       data_set->add_data_field (ptr);
+
+       // EAN13MetadataField is the only kind of MetadataField which has a status label.
+       EAN13MetadataField &emf = (EAN13MetadataField &) *ptr;
+       ((Gtk::VBox &) data_set->get_widget()).pack_end (*emf.status_label);
+       emf.update_status ();
 }
 
 template <typename DataSet>
@@ -576,39 +806,56 @@ SessionMetadataDialog<DataSet>::init_people_data ()
        data_list.push_back (data_set);
 
        MetadataPtr ptr;
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer")));
        data_set->add_data_field (ptr);
-       
+
        ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer")));
        data_set->add_data_field (ptr);
-       
-       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, _("Mixer")));
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, S_("Metadata|Mixer")));
        data_set->add_data_field (ptr);
 }
 
+template <typename DataSet>
+void
+SessionMetadataDialog<DataSet>::init_school_data ()
+{
+       DataSetPtr data_set (new DataSet (_("School")));
+       data_list.push_back (data_set);
+
+       MetadataPtr ptr;
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::instructor, &ARDOUR::SessionMetadata::set_instructor, _("Instructor")));
+       data_set->add_data_field (ptr);
+
+       ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::course, &ARDOUR::SessionMetadata::set_course, _("Course")));
+       data_set->add_data_field (ptr);
+
+}
+
 /* SessionMetadataEditor */
 
 SessionMetadataEditor::SessionMetadataEditor () :
-  SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit session metadata"))
+  SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit Session Metadata"))
 {
 
 }
@@ -621,10 +868,10 @@ SessionMetadataEditor::~SessionMetadataEditor ()
 
 void
 SessionMetadataEditor::run ()
-{      
+{
        init_data ();
        init_gui();
-       
+
        ArdourDialog::run();
 }
 
@@ -632,7 +879,7 @@ void
 SessionMetadataEditor::init_gui ()
 {
        add_widget (notebook);
-       
+
        show_all();
 }
 
@@ -652,22 +899,22 @@ SessionMetadataImporter::~SessionMetadataImporter ()
 
 void
 SessionMetadataImporter::run ()
-{      
-       if (!session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl;
+{
+       if (!_session) {
+               error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataImporter (in run)!") << endmsg;
                return;
        }
 
        /* Open session file selector */
-       
+
        Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN);
        session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
        session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
        session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
 
        Gtk::FileFilter session_filter;
-       session_filter.add_pattern ("*.ardour");
-       session_filter.set_name (_("Ardour sessions"));
+       session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
+       session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
        session_selector.add_filter (session_filter);
        session_selector.set_filter (session_filter);
 
@@ -692,30 +939,33 @@ SessionMetadataImporter::run ()
        } else {
                return;
        }
-       
+
        /* We have a session: load the data and run dialog */
-       
-       string filename = Glib::build_filename (path, name + ".ardour");
+
+       string filename = Glib::build_filename (path, name + ARDOUR::statefile_suffix);
        XMLTree session_tree;
        if (!session_tree.read (filename)) {
-               warn_user (_("A proper ardour session file was not selected!"));
+               warn_user (_("This session file could not be read!"));
                return;
        }
-       
+
+       /* XXX GET VERSION FROM TREE */
+       int version = 3000;
+
        XMLNode * node = session_tree.root()->child ("Metadata");
-       
+
        if (!node) {
                warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
                return;
        }
-       
+
+       //create a temporary
        ARDOUR::SessionMetadata data;
-       data.set_state (*node);
-       
-       init_data ();
+       data.set_state (*node, version);
+       init_data ( true );  //skip user data here
        load_extra_data (data);
        init_gui();
-       
+
        ArdourDialog::run();
 }
 
@@ -726,13 +976,13 @@ SessionMetadataImporter::init_gui ()
        add_widget (selection_hbox);
        selection_label.set_text (_("Import all from:"));
        selection_hbox.pack_start (selection_label, false, false);
-       
+
        WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget);
        for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) {
                selection_hbox.pack_start (**it, false, false, 6);
        }
 
        add_widget (notebook);
-       
+
        show_all();
 }