Speed up AFL/PFL changes for large sessions
[ardour.git] / gtk2_ardour / session_metadata_dialog.cc
index 996262f0fac49ed99451f7ea8c98504ca4aed8dc..a4cfee2b1047ff33aa78eca0955fb3419553cdfa 100644 (file)
 #include <gtkmm2ext/utils.h>
 
 #include "pbd/xml++.h"
+#include "pbd/error.h"
+
+#include "ardour/filename_extensions.h"
 #include "ardour/session.h"
-#include "ardour/session_directory.h"
 #include "ardour/session_utils.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace std;
 using namespace Glib;
+using namespace PBD;
 
 #define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
 
@@ -81,8 +84,8 @@ TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
 Gtk::Widget &
 TextMetadataField::name_widget ()
 {
-       label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
-       label->set_alignment (0, 0.5);
+       label = Gtk::manage (new Gtk::Label(_name + ':'));
+       label->set_alignment (1, 0.5);
        return *label;
 }
 
@@ -151,7 +154,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);
@@ -160,8 +163,8 @@ NumberMetadataField::update_value ()
 Gtk::Widget &
 NumberMetadataField::name_widget ()
 {
-       label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
-       label->set_alignment (0, 0.5);
+       label = Gtk::manage (new Gtk::Label(_name + ':'));
+       label->set_alignment (1, 0.5);
        return *label;
 }
 
@@ -213,6 +216,129 @@ NumberMetadataField::str_to_uint (string 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.5);
+       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 (string const & name)
@@ -255,7 +381,7 @@ SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
                return;
        }
 
-       ARDOUR::SessionMetadata const & data = _session->metadata();
+       ARDOUR::SessionMetadata const & data = *(ARDOUR::SessionMetadata::Metadata());
 
        table.resize (list.size(), 2);
        uint32_t row = 0;
@@ -272,7 +398,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);
        }
@@ -326,11 +452,11 @@ 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;
+               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;
@@ -374,11 +500,11 @@ void
 SessionMetadataSetImportable::save_data ()
 {
        if (!_session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl;
+               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;
@@ -421,22 +547,25 @@ SessionMetadataDialog<DataSet>::SessionMetadataDialog (string const & name) :
 {
        cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
        cancel_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::end_dialog));
-       save_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
+       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;
+               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 ();
 
        for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
                (*it)->set_session (_session);
@@ -468,6 +597,7 @@ void
 SessionMetadataDialog<DataSet>::save_and_close ()
 {
        save_data ();
+       _session->set_dirty();
        end_dialog ();
 }
 
@@ -507,6 +637,32 @@ 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_track_data ()
@@ -576,6 +732,14 @@ SessionMetadataDialog<DataSet>::init_album_data ()
 
        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>
@@ -615,6 +779,23 @@ SessionMetadataDialog<DataSet>::init_people_data ()
        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 () :
@@ -664,7 +845,7 @@ void
 SessionMetadataImporter::run ()
 {
        if (!_session) {
-               std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl;
+               error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataImporter (in run)!") << endmsg;
                return;
        }
 
@@ -676,7 +857,7 @@ SessionMetadataImporter::run ()
        session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
 
        Gtk::FileFilter session_filter;
-       session_filter.add_pattern ("*.ardour");
+       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);
@@ -705,7 +886,7 @@ SessionMetadataImporter::run ()
 
        /* 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 (_("This session file could not be read!"));
@@ -722,10 +903,10 @@ SessionMetadataImporter::run ()
                return;
        }
 
+       //create a temporary
        ARDOUR::SessionMetadata data;
        data.set_state (*node, version);
-
-       init_data ();
+       init_data ( true );  //skip user data here
        load_extra_data (data);
        init_gui();