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>
25 #include <gtkmm2ext/window_title.h>
28 #include "pbd/xml++.h"
29 #include "ardour/session.h"
30 #include "ardour/session_directory.h"
31 #include "ardour/session_utils.h"
36 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
38 /*** MetadataField ***/
40 MetadataField::MetadataField (ustring const & field_name) :
45 MetadataField::~MetadataField() { }
47 /* TextMetadataField */
49 TextMetadataField::TextMetadataField (Getter getter, Setter setter, ustring const & field_name, guint width ) :
50 MetadataField (field_name),
61 TextMetadataField::copy ()
63 return MetadataPtr (new TextMetadataField (getter, setter, _name, width));
67 TextMetadataField::save_data (ARDOUR::SessionMetadata & data) const
69 CALL_MEMBER_FN (data, setter) (_value);
73 TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
75 _value = CALL_MEMBER_FN (data, getter) ();
77 entry->set_text (_value);
82 TextMetadataField::name_widget ()
84 label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
89 TextMetadataField::value_widget ()
91 value_label = Gtk::manage (new Gtk::Label(_value));
96 TextMetadataField::edit_widget ()
98 entry = Gtk::manage (new Gtk::Entry());
100 entry->set_text (_value);
101 entry->set_width_chars (width);
102 entry->signal_changed().connect (sigc::mem_fun(*this, &TextMetadataField::update_value));
108 TextMetadataField::update_value ()
110 _value = entry->get_text ();
113 /* NumberMetadataField */
115 NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, ustring const & field_name, guint numbers, guint width) :
116 MetadataField (field_name),
128 NumberMetadataField::copy ()
130 return MetadataPtr (new NumberMetadataField (getter, setter, _name, numbers, width));
134 NumberMetadataField::save_data (ARDOUR::SessionMetadata & data) const
136 uint32_t number = str_to_uint (_value);
137 CALL_MEMBER_FN (data, setter) (number);
141 NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data)
143 uint32_t number = CALL_MEMBER_FN (data, getter) ();
144 _value = uint_to_str (number);
146 entry->set_text (_value);
151 NumberMetadataField::update_value ()
153 // Accpt only numbers
154 uint32_t number = str_to_uint (entry->get_text());
155 _value = uint_to_str (number);
156 entry->set_text (_value);
160 NumberMetadataField::name_widget ()
162 label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
167 NumberMetadataField::value_widget ()
169 value_label = Gtk::manage (new Gtk::Label(_value));
174 NumberMetadataField::edit_widget ()
176 entry = Gtk::manage (new Gtk::Entry());
178 entry->set_text (_value);
179 entry->set_width_chars (width);
180 entry->set_max_length (numbers);
181 entry->signal_changed().connect (sigc::mem_fun(*this, &NumberMetadataField::update_value));
187 NumberMetadataField::uint_to_str (uint32_t i) const
189 std::ostringstream oss ("");
191 if (oss.str().compare("0")) {
199 NumberMetadataField::str_to_uint (ustring const & str) const
202 ustring::size_type i;
203 while ((i = tmp.find_first_not_of("1234567890")) != ustring::npos) {
207 std::istringstream iss(tmp);
214 /* SessionMetadataSet */
216 SessionMetadataSet::SessionMetadataSet (ustring const & name) :
223 SessionMetadataSet::add_data_field (MetadataPtr field)
225 list.push_back (field);
228 /* SessionMetadataSetEditable */
230 SessionMetadataSetEditable::SessionMetadataSetEditable (ustring const & name) :
231 SessionMetadataSet (name)
233 table.set_row_spacings (6);
234 table.set_col_spacings (12);
238 SessionMetadataSetEditable::get_tab_widget ()
240 tab_widget.set_text (name);
245 SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
249 ARDOUR::SessionMetadata const & data = session->metadata();
251 table.resize (list.size(), 2);
254 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
256 field->load_data (data);
257 table.attach (field->name_widget(), 0, 1, row, row + 1);
258 table.attach (field->edit_widget(), 1, 2, row, row + 1);
264 SessionMetadataSetEditable::save_data ()
266 ARDOUR::SessionMetadata & data = session->metadata();
267 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
268 (*it)->save_data(data);
272 /* SessionMetadataSetImportable */
274 SessionMetadataSetImportable::SessionMetadataSetImportable (ustring const & name) :
275 SessionMetadataSet (name),
278 tree = Gtk::ListStore::create (tree_cols);
279 tree_view.set_model (tree);
281 Gtk::TreeView::Column * viewcol;
284 Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle());
285 import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed));
286 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render));
287 viewcol->add_attribute (import_render->property_active(), tree_cols.import);
288 tree_view.append_column (*viewcol);
290 // Add field name column
291 tree_view.append_column(_("Field"), tree_cols.field);
293 // Add values column with pango markup
294 Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText());
295 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render));
296 viewcol->add_attribute (values_render->property_markup(), tree_cols.values);
297 tree_view.append_column (*viewcol);
299 select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all));
305 SessionMetadataSetImportable::get_tab_widget ()
307 tab_widget.set_text (name);
312 SessionMetadataSetImportable::get_select_all_widget ()
314 select_all_check.set_label (name);
315 return select_all_check;
319 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data)
322 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl;
326 ARDOUR::SessionMetadata & session_data = session->metadata();
328 MetadataPtr session_field;
329 MetadataPtr import_field;
330 DataList::iterator session_it;
331 DataList::iterator import_it;
333 // Copy list and load data to import
334 for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) {
335 session_field = *session_it;
336 session_field->load_data(session_data);
337 import_list.push_back (session_field->copy());
341 session_it = session_list.begin();
342 import_it = import_list.begin();
343 while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same...
344 session_field = *session_it;
345 import_field = *import_it;
347 import_field->load_data(data); // hasn't been done yet
349 // Make string for values TODO get color from somewhere?
350 ustring values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
351 + "<span weight=\"bold\">" + import_field->value() + "</span>";
353 Gtk::TreeModel::iterator row_iter = tree->append();
354 Gtk::TreeModel::Row row = *row_iter;
356 row[tree_cols.field] = import_field->name();
357 row[tree_cols.values] = values;
358 row[tree_cols.import] = false;
359 row[tree_cols.data] = import_field;
367 SessionMetadataSetImportable::save_data ()
370 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl;
374 ARDOUR::SessionMetadata & session_data = session->metadata();
376 Gtk::TreeModel::Children fields = tree->children();
377 Gtk::TreeModel::Children::iterator it;
378 for (it = fields.begin(); it != fields.end(); ++it) {
379 if ((*it)[tree_cols.import]) {
380 MetadataPtr field = (*it)[tree_cols.data];
381 field->save_data (session_data);
387 SessionMetadataSetImportable::select_all ()
389 select_all_check.set_inconsistent (false);
390 bool state = select_all_check.get_active();
392 Gtk::TreeModel::Children fields = tree->children();
393 Gtk::TreeModel::Children::iterator it;
394 for (it = fields.begin(); it != fields.end(); ++it) {
395 (*it)[tree_cols.import] = state;
400 SessionMetadataSetImportable::selection_changed (ustring const & path)
402 select_all_check.set_inconsistent (true);
404 Gtk::TreeModel::iterator iter = tree->get_iter (path);
405 bool value((*iter)[tree_cols.import]);
406 (*iter)[tree_cols.import] = !value;
409 /* SessionMetadataDialog */
411 template <typename DataSet>
412 SessionMetadataDialog<DataSet>::SessionMetadataDialog (ustring const & name) :
413 ArdourDialog (name, true)
415 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
416 cancel_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::end_dialog));
417 save_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
418 save_button->signal_clicked().connect (mem_fun(*this, &SessionMetadataDialog::save_and_close));
421 template <typename DataSet>
423 SessionMetadataDialog<DataSet>::init_data ()
426 std::cerr << "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl;
434 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
435 (*it)->set_session (session);
437 notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget());
441 template <typename DataSet>
443 SessionMetadataDialog<DataSet>::load_extra_data (ARDOUR::SessionMetadata const & data)
445 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
446 (*it)->load_extra_data (data);
450 template <typename DataSet>
452 SessionMetadataDialog<DataSet>::save_data ()
454 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
459 template <typename DataSet>
461 SessionMetadataDialog<DataSet>::save_and_close ()
467 template <typename DataSet>
469 SessionMetadataDialog<DataSet>::end_dialog ()
474 template <typename DataSet>
476 SessionMetadataDialog<DataSet>::warn_user (ustring const & string)
478 Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
482 template <typename DataSet>
483 boost::shared_ptr<std::list<Gtk::Widget *> >
484 SessionMetadataDialog<DataSet>::get_custom_widgets (WidgetFunc f)
486 WidgetListPtr list (new WidgetList);
487 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it)
489 DataSet * set = dynamic_cast<DataSet *> (it->get());
490 list->push_back (& CALL_MEMBER_FN (*set, f) ());
496 template <typename DataSet>
498 SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
500 get_vbox()->pack_start (widget, true, true, 0);
503 template <typename DataSet>
505 SessionMetadataDialog<DataSet>::init_track_data ()
507 DataSetPtr data_set (new DataSet (_("Track")));
508 data_list.push_back (data_set);
512 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title")));
513 data_set->add_data_field (ptr);
515 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3));
516 data_set->add_data_field (ptr);
518 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle")));
519 data_set->add_data_field (ptr);
521 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping")));
522 data_set->add_data_field (ptr);
524 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist")));
525 data_set->add_data_field (ptr);
527 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre")));
528 data_set->add_data_field (ptr);
530 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment")));
531 data_set->add_data_field (ptr);
533 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright")));
534 data_set->add_data_field (ptr);
537 template <typename DataSet>
539 SessionMetadataDialog<DataSet>::init_album_data ()
541 DataSetPtr data_set (new DataSet (_("Album")));
542 data_list.push_back (data_set);
546 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album")));
547 data_set->add_data_field (ptr);
549 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4));
550 data_set->add_data_field (ptr);
552 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist")));
553 data_set->add_data_field (ptr);
555 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3));
556 data_set->add_data_field (ptr);
558 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle")));
559 data_set->add_data_field (ptr);
561 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2));
562 data_set->add_data_field (ptr);
564 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2));
565 data_set->add_data_field (ptr);
567 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation")));
568 data_set->add_data_field (ptr);
570 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC")));
571 data_set->add_data_field (ptr);
574 template <typename DataSet>
576 SessionMetadataDialog<DataSet>::init_people_data ()
578 DataSetPtr data_set (new DataSet (_("People")));
579 data_list.push_back (data_set);
583 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist")));
584 data_set->add_data_field (ptr);
586 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer")));
587 data_set->add_data_field (ptr);
589 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor")));
590 data_set->add_data_field (ptr);
592 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer")));
593 data_set->add_data_field (ptr);
595 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger")));
596 data_set->add_data_field (ptr);
598 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer")));
599 data_set->add_data_field (ptr);
601 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer")));
602 data_set->add_data_field (ptr);
604 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer")));
605 data_set->add_data_field (ptr);
607 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, _("Mixer")));
608 data_set->add_data_field (ptr);
611 /* SessionMetadataEditor */
613 SessionMetadataEditor::SessionMetadataEditor () :
614 SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit session metadata"))
619 SessionMetadataEditor::~SessionMetadataEditor ()
621 // Remove pages from notebook to get rid of gsignal runtime warnings
622 notebook.pages().clear();
626 SessionMetadataEditor::run ()
635 SessionMetadataEditor::init_gui ()
637 add_widget (notebook);
642 /* SessionMetadataImporter */
644 SessionMetadataImporter::SessionMetadataImporter () :
645 SessionMetadataDialog<SessionMetadataSetImportable> (_("Import session metadata"))
650 SessionMetadataImporter::~SessionMetadataImporter ()
652 // Remove pages from notebook to get rid of gsignal runtime warnings
653 notebook.pages().clear();
657 SessionMetadataImporter::run ()
660 std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl;
664 /* Open session file selector */
666 Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN);
667 session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
668 session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
669 session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
671 Gtk::FileFilter session_filter;
672 session_filter.add_pattern ("*.ardour");
673 session_filter.set_name (_("Ardour sessions"));
674 session_selector.add_filter (session_filter);
675 session_selector.set_filter (session_filter);
677 int response = session_selector.run();
678 session_selector.hide ();
681 case Gtk::RESPONSE_ACCEPT:
687 string session_path = session_selector.get_filename();
691 if (session_path.length() > 0) {
692 if (ARDOUR::find_session (session_path, path, name, isnew) != 0) {
699 /* We have a session: load the data and run dialog */
701 string filename = Glib::build_filename (path, name + ".ardour");
702 XMLTree session_tree;
703 if (!session_tree.read (filename)) {
704 warn_user (_("A proper ardour session file was not selected!"));
708 XMLNode * node = session_tree.root()->child ("Metadata");
711 warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
715 ARDOUR::SessionMetadata data;
716 data.set_state (*node);
719 load_extra_data (data);
726 SessionMetadataImporter::init_gui ()
728 // Select all from -widget
729 add_widget (selection_hbox);
730 selection_label.set_text (_("Import all from:"));
731 selection_hbox.pack_start (selection_label, false, false);
733 WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget);
734 for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) {
735 selection_hbox.pack_start (**it, false, false, 6);
738 add_widget (notebook);