2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2 of the License, or (at your option)
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "session_metadata_dialog.h"
24 #include <gtkmm2ext/utils.h>
26 #include "pbd/xml++.h"
27 #include "ardour/session.h"
28 #include "ardour/session_directory.h"
29 #include "ardour/session_utils.h"
30 #include "ardour/configuration.h"
37 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
39 /*** MetadataField ***/
41 MetadataField::MetadataField (string const & field_name) :
46 MetadataField::~MetadataField() { }
48 /* TextMetadataField */
50 TextMetadataField::TextMetadataField (Getter getter, Setter setter, string const & field_name, guint width ) :
51 MetadataField (field_name),
62 TextMetadataField::copy ()
64 return MetadataPtr (new TextMetadataField (getter, setter, _name, width));
68 TextMetadataField::save_data (ARDOUR::SessionMetadata & data) const
70 CALL_MEMBER_FN (data, setter) (_value);
74 TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
76 _value = CALL_MEMBER_FN (data, getter) ();
78 entry->set_text (_value);
83 TextMetadataField::name_widget ()
85 label = Gtk::manage (new Gtk::Label(_name + ':'));
86 label->set_alignment (1, 0.5);
91 TextMetadataField::value_widget ()
93 value_label = Gtk::manage (new Gtk::Label(_value));
98 TextMetadataField::edit_widget ()
100 entry = Gtk::manage (new Gtk::Entry());
102 entry->set_text (_value);
103 entry->set_width_chars (width);
104 entry->signal_changed().connect (sigc::mem_fun(*this, &TextMetadataField::update_value));
110 TextMetadataField::update_value ()
112 _value = entry->get_text ();
115 /* NumberMetadataField */
117 NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, string const & field_name, guint numbers, guint width) :
118 MetadataField (field_name),
130 NumberMetadataField::copy ()
132 return MetadataPtr (new NumberMetadataField (getter, setter, _name, numbers, width));
136 NumberMetadataField::save_data (ARDOUR::SessionMetadata & data) const
138 uint32_t number = str_to_uint (_value);
139 CALL_MEMBER_FN (data, setter) (number);
143 NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data)
145 uint32_t number = CALL_MEMBER_FN (data, getter) ();
146 _value = uint_to_str (number);
148 entry->set_text (_value);
153 NumberMetadataField::update_value ()
155 // Accpt only numbers
156 uint32_t number = str_to_uint (entry->get_text());
157 _value = uint_to_str (number);
158 entry->set_text (_value);
162 NumberMetadataField::name_widget ()
164 label = Gtk::manage (new Gtk::Label(_name + ':'));
165 label->set_alignment (1, 0.5);
170 NumberMetadataField::value_widget ()
172 value_label = Gtk::manage (new Gtk::Label(_value));
177 NumberMetadataField::edit_widget ()
179 entry = Gtk::manage (new Gtk::Entry());
181 entry->set_text (_value);
182 entry->set_width_chars (width);
183 entry->set_max_length (numbers);
184 entry->signal_changed().connect (sigc::mem_fun(*this, &NumberMetadataField::update_value));
190 NumberMetadataField::uint_to_str (uint32_t i) const
192 std::ostringstream oss ("");
194 if (oss.str().compare("0")) {
202 NumberMetadataField::str_to_uint (string const & str) const
206 while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
210 std::istringstream iss(tmp);
217 /* SessionMetadataSet */
219 SessionMetadataSet::SessionMetadataSet (string const & name)
225 SessionMetadataSet::add_data_field (MetadataPtr field)
227 list.push_back (field);
230 /* SessionMetadataSetEditable */
232 SessionMetadataSetEditable::SessionMetadataSetEditable (string const & name)
233 : SessionMetadataSet (name)
235 table.set_row_spacings (6);
236 table.set_col_spacings (12);
237 table.set_homogeneous (false);
238 vbox.pack_start (table, false, false);
239 vbox.set_spacing (6);
240 vbox.set_border_width (6);
244 SessionMetadataSetEditable::get_tab_widget ()
246 tab_widget.set_text (name);
251 SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
253 SessionHandlePtr::set_session (s);
259 ARDOUR::SessionMetadata const & data = *(ARDOUR::SessionMetadata::Metadata());
261 table.resize (list.size(), 2);
264 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
266 field->load_data (data);
267 table.attach (field->name_widget(), 0, 1, row, row + 1, Gtk::FILL);
268 table.attach (field->edit_widget(), 1, 2, row, row + 1);
274 SessionMetadataSetEditable::save_data ()
276 ARDOUR::SessionMetadata & data = *(ARDOUR::SessionMetadata::Metadata());
277 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
278 (*it)->save_data(data);
282 /* SessionMetadataSetImportable */
284 SessionMetadataSetImportable::SessionMetadataSetImportable (string const & name)
285 : SessionMetadataSet (name)
286 , session_list (list)
288 tree = Gtk::ListStore::create (tree_cols);
289 tree_view.set_model (tree);
291 Gtk::TreeView::Column * viewcol;
294 Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle());
295 import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed));
296 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render));
297 viewcol->add_attribute (import_render->property_active(), tree_cols.import);
298 tree_view.append_column (*viewcol);
300 // Add field name column
301 tree_view.append_column(_("Field"), tree_cols.field);
303 // Add values column with pango markup
304 Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText());
305 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render));
306 viewcol->add_attribute (values_render->property_markup(), tree_cols.values);
307 tree_view.append_column (*viewcol);
309 select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all));
313 SessionMetadataSetImportable::get_tab_widget ()
315 tab_widget.set_text (name);
320 SessionMetadataSetImportable::get_select_all_widget ()
322 select_all_check.set_label (name);
323 return select_all_check;
327 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data)
330 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl;
334 ARDOUR::SessionMetadata const & session_data = *(ARDOUR::SessionMetadata::Metadata());
336 MetadataPtr session_field;
337 MetadataPtr import_field;
338 DataList::iterator session_it;
339 DataList::iterator import_it;
341 // Copy list and load data to import
342 for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) {
343 session_field = *session_it;
344 session_field->load_data(session_data);
345 import_list.push_back (session_field->copy());
349 session_it = session_list.begin();
350 import_it = import_list.begin();
351 while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same...
352 session_field = *session_it;
353 import_field = *import_it;
355 import_field->load_data(data); // hasn't been done yet
357 // Make string for values TODO get color from somewhere?
358 string values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
359 + "<span weight=\"bold\">" + import_field->value() + "</span>";
361 Gtk::TreeModel::iterator row_iter = tree->append();
362 Gtk::TreeModel::Row row = *row_iter;
364 row[tree_cols.field] = import_field->name();
365 row[tree_cols.values] = values;
366 row[tree_cols.import] = false;
367 row[tree_cols.data] = import_field;
375 SessionMetadataSetImportable::save_data ()
378 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl;
382 ARDOUR::SessionMetadata & session_data = *(ARDOUR::SessionMetadata::Metadata());
384 Gtk::TreeModel::Children fields = tree->children();
385 Gtk::TreeModel::Children::iterator it;
386 for (it = fields.begin(); it != fields.end(); ++it) {
387 if ((*it)[tree_cols.import]) {
388 MetadataPtr field = (*it)[tree_cols.data];
389 field->save_data (session_data);
395 SessionMetadataSetImportable::select_all ()
397 select_all_check.set_inconsistent (false);
398 bool state = select_all_check.get_active();
400 Gtk::TreeModel::Children fields = tree->children();
401 Gtk::TreeModel::Children::iterator it;
402 for (it = fields.begin(); it != fields.end(); ++it) {
403 (*it)[tree_cols.import] = state;
408 SessionMetadataSetImportable::selection_changed (string const & path)
410 select_all_check.set_inconsistent (true);
412 Gtk::TreeModel::iterator iter = tree->get_iter (path);
413 bool value((*iter)[tree_cols.import]);
414 (*iter)[tree_cols.import] = !value;
417 /* SessionMetadataDialog */
419 template <typename DataSet>
420 SessionMetadataDialog<DataSet>::SessionMetadataDialog (string const & name) :
421 ArdourDialog (name, true)
423 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
424 cancel_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::end_dialog));
425 save_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
426 save_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::save_and_close));
429 template <typename DataSet>
431 SessionMetadataDialog<DataSet>::init_data ( bool skip_user )
434 std::cerr << "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl;
445 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
446 (*it)->set_session (_session);
448 notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget());
452 template <typename DataSet>
454 SessionMetadataDialog<DataSet>::load_extra_data (ARDOUR::SessionMetadata const & data)
456 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
457 (*it)->load_extra_data (data);
461 template <typename DataSet>
463 SessionMetadataDialog<DataSet>::save_data ()
465 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
470 template <typename DataSet>
472 SessionMetadataDialog<DataSet>::save_and_close ()
475 _session->set_dirty();
479 template <typename DataSet>
481 SessionMetadataDialog<DataSet>::end_dialog ()
486 template <typename DataSet>
488 SessionMetadataDialog<DataSet>::warn_user (string const & string)
490 Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
494 template <typename DataSet>
495 boost::shared_ptr<std::list<Gtk::Widget *> >
496 SessionMetadataDialog<DataSet>::get_custom_widgets (WidgetFunc f)
498 WidgetListPtr list (new WidgetList);
499 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it)
501 DataSet * set = dynamic_cast<DataSet *> (it->get());
502 list->push_back (& CALL_MEMBER_FN (*set, f) ());
508 template <typename DataSet>
510 SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
512 get_vbox()->pack_start (widget, true, true, 0);
515 template <typename DataSet>
517 SessionMetadataDialog<DataSet>::init_user_data ()
519 DataSetPtr data_set (new DataSet (_("User")));
520 data_list.push_back (data_set);
524 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_name, &ARDOUR::SessionMetadata::set_user_name, _("Name")));
525 data_set->add_data_field (ptr);
527 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_email, &ARDOUR::SessionMetadata::set_user_email, _("Email")));
528 data_set->add_data_field (ptr);
530 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_web, &ARDOUR::SessionMetadata::set_user_web, _("Web")));
531 data_set->add_data_field (ptr);
533 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::organization, &ARDOUR::SessionMetadata::set_organization, _("Organization")));
534 data_set->add_data_field (ptr);
536 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::country, &ARDOUR::SessionMetadata::set_country, _("Country")));
537 data_set->add_data_field (ptr);
541 template <typename DataSet>
543 SessionMetadataDialog<DataSet>::init_track_data ()
545 DataSetPtr data_set (new DataSet (_("Track")));
546 data_list.push_back (data_set);
550 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title")));
551 data_set->add_data_field (ptr);
553 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3));
554 data_set->add_data_field (ptr);
556 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle")));
557 data_set->add_data_field (ptr);
559 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping")));
560 data_set->add_data_field (ptr);
562 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist")));
563 data_set->add_data_field (ptr);
565 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre")));
566 data_set->add_data_field (ptr);
568 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment")));
569 data_set->add_data_field (ptr);
571 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright")));
572 data_set->add_data_field (ptr);
575 template <typename DataSet>
577 SessionMetadataDialog<DataSet>::init_album_data ()
579 DataSetPtr data_set (new DataSet (_("Album")));
580 data_list.push_back (data_set);
584 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album")));
585 data_set->add_data_field (ptr);
587 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4));
588 data_set->add_data_field (ptr);
590 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist")));
591 data_set->add_data_field (ptr);
593 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3));
594 data_set->add_data_field (ptr);
596 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle")));
597 data_set->add_data_field (ptr);
599 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2));
600 data_set->add_data_field (ptr);
602 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2));
603 data_set->add_data_field (ptr);
605 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation")));
606 data_set->add_data_field (ptr);
608 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC")));
609 data_set->add_data_field (ptr);
612 template <typename DataSet>
614 SessionMetadataDialog<DataSet>::init_people_data ()
616 DataSetPtr data_set (new DataSet (_("People")));
617 data_list.push_back (data_set);
621 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist")));
622 data_set->add_data_field (ptr);
624 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer")));
625 data_set->add_data_field (ptr);
627 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor")));
628 data_set->add_data_field (ptr);
630 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer")));
631 data_set->add_data_field (ptr);
633 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger")));
634 data_set->add_data_field (ptr);
636 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer")));
637 data_set->add_data_field (ptr);
639 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer")));
640 data_set->add_data_field (ptr);
642 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer")));
643 data_set->add_data_field (ptr);
645 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, S_("Metadata|Mixer")));
646 data_set->add_data_field (ptr);
649 template <typename DataSet>
651 SessionMetadataDialog<DataSet>::init_school_data ()
653 DataSetPtr data_set (new DataSet (_("School")));
654 data_list.push_back (data_set);
658 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::instructor, &ARDOUR::SessionMetadata::set_instructor, _("Instructor")));
659 data_set->add_data_field (ptr);
661 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::course, &ARDOUR::SessionMetadata::set_course, _("Course")));
662 data_set->add_data_field (ptr);
666 /* SessionMetadataEditor */
668 SessionMetadataEditor::SessionMetadataEditor () :
669 SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit Session Metadata"))
674 SessionMetadataEditor::~SessionMetadataEditor ()
676 // Remove pages from notebook to get rid of gsignal runtime warnings
677 notebook.pages().clear();
681 SessionMetadataEditor::run ()
690 SessionMetadataEditor::init_gui ()
692 add_widget (notebook);
697 /* SessionMetadataImporter */
699 SessionMetadataImporter::SessionMetadataImporter () :
700 SessionMetadataDialog<SessionMetadataSetImportable> (_("Import session metadata"))
705 SessionMetadataImporter::~SessionMetadataImporter ()
707 // Remove pages from notebook to get rid of gsignal runtime warnings
708 notebook.pages().clear();
712 SessionMetadataImporter::run ()
715 std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl;
719 /* Open session file selector */
721 Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN);
722 session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
723 session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
724 session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
726 Gtk::FileFilter session_filter;
727 session_filter.add_pattern ("*.ardour");
728 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
729 session_selector.add_filter (session_filter);
730 session_selector.set_filter (session_filter);
732 int response = session_selector.run();
733 session_selector.hide ();
736 case Gtk::RESPONSE_ACCEPT:
742 string session_path = session_selector.get_filename();
746 if (session_path.length() > 0) {
747 if (ARDOUR::find_session (session_path, path, name, isnew) != 0) {
754 /* We have a session: load the data and run dialog */
756 string filename = Glib::build_filename (path, name + ".ardour");
757 XMLTree session_tree;
758 if (!session_tree.read (filename)) {
759 warn_user (_("This session file could not be read!"));
763 /* XXX GET VERSION FROM TREE */
766 XMLNode * node = session_tree.root()->child ("Metadata");
769 warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
774 ARDOUR::SessionMetadata data;
775 data.set_state (*node, version);
776 init_data ( true ); //skip user data here
777 load_extra_data (data);
784 SessionMetadataImporter::init_gui ()
786 // Select all from -widget
787 add_widget (selection_hbox);
788 selection_label.set_text (_("Import all from:"));
789 selection_hbox.pack_start (selection_label, false, false);
791 WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget);
792 for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) {
793 selection_hbox.pack_start (**it, false, false, 6);
796 add_widget (notebook);