Copy local state in AudioRegionView copy constructor. Fixes #4047.
[ardour2.git] / gtk2_ardour / session_metadata_dialog.cc
blobe43762548088afda5d07d1d724fd37c99ed809f4
1 /*
2 Copyright (C) 2008 Paul Davis
3 Author: Sakari Bergen
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)
8 any later version.
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
13 for more details.
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"
22 #include <sstream>
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"
31 #include "i18n.h"
33 using namespace std;
34 using namespace Glib;
36 #define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember))
38 /*** MetadataField ***/
40 MetadataField::MetadataField (string const & field_name) :
41 _name (field_name)
45 MetadataField::~MetadataField() { }
47 /* TextMetadataField */
49 TextMetadataField::TextMetadataField (Getter getter, Setter setter, string const & field_name, guint width ) :
50 MetadataField (field_name),
51 getter (getter),
52 setter (setter),
53 width (width)
55 entry = 0;
56 label = 0;
57 value_label = 0;
60 MetadataPtr
61 TextMetadataField::copy ()
63 return MetadataPtr (new TextMetadataField (getter, setter, _name, width));
66 void
67 TextMetadataField::save_data (ARDOUR::SessionMetadata & data) const
69 CALL_MEMBER_FN (data, setter) (_value);
72 void
73 TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
75 _value = CALL_MEMBER_FN (data, getter) ();
76 if (entry) {
77 entry->set_text (_value);
81 Gtk::Widget &
82 TextMetadataField::name_widget ()
84 label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
85 return *label;
88 Gtk::Widget &
89 TextMetadataField::value_widget ()
91 value_label = Gtk::manage (new Gtk::Label(_value));
92 return *value_label;
95 Gtk::Widget &
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));
104 return *entry;
107 void
108 TextMetadataField::update_value ()
110 _value = entry->get_text ();
113 /* NumberMetadataField */
115 NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, string const & field_name, guint numbers, guint width) :
116 MetadataField (field_name),
117 getter (getter),
118 setter (setter),
119 numbers (numbers),
120 width (width)
122 entry = 0;
123 label = 0;
124 value_label = 0;
127 MetadataPtr
128 NumberMetadataField::copy ()
130 return MetadataPtr (new NumberMetadataField (getter, setter, _name, numbers, width));
133 void
134 NumberMetadataField::save_data (ARDOUR::SessionMetadata & data) const
136 uint32_t number = str_to_uint (_value);
137 CALL_MEMBER_FN (data, setter) (number);
140 void
141 NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data)
143 uint32_t number = CALL_MEMBER_FN (data, getter) ();
144 _value = uint_to_str (number);
145 if (entry) {
146 entry->set_text (_value);
150 void
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);
159 Gtk::Widget &
160 NumberMetadataField::name_widget ()
162 label = Gtk::manage (new Gtk::Label(_name + ':', Gtk::ALIGN_LEFT));
163 return *label;
166 Gtk::Widget &
167 NumberMetadataField::value_widget ()
169 value_label = Gtk::manage (new Gtk::Label(_value));
170 return *value_label;
173 Gtk::Widget &
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));
183 return *entry;
186 string
187 NumberMetadataField::uint_to_str (uint32_t i) const
189 std::ostringstream oss ("");
190 oss << i;
191 if (oss.str().compare("0")) {
192 return oss.str();
193 } else {
194 return "";
198 uint32_t
199 NumberMetadataField::str_to_uint (string const & str) const
201 string tmp (str);
202 string::size_type i;
203 while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
204 tmp.erase (i, 1);
207 std::istringstream iss(tmp);
208 uint32_t result = 0;
209 iss >> result;
210 return result;
214 /* SessionMetadataSet */
216 SessionMetadataSet::SessionMetadataSet (string const & name)
217 : name (name)
221 void
222 SessionMetadataSet::add_data_field (MetadataPtr field)
224 list.push_back (field);
227 /* SessionMetadataSetEditable */
229 SessionMetadataSetEditable::SessionMetadataSetEditable (string const & name)
230 : SessionMetadataSet (name)
232 table.set_row_spacings (6);
233 table.set_col_spacings (12);
234 vbox.pack_start (table, false, false);
235 vbox.set_spacing (6);
236 vbox.set_border_width (6);
239 Gtk::Widget &
240 SessionMetadataSetEditable::get_tab_widget ()
242 tab_widget.set_text (name);
243 return tab_widget;
246 void
247 SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
249 SessionHandlePtr::set_session (s);
251 if (!_session) {
252 return;
255 ARDOUR::SessionMetadata const & data = _session->metadata();
257 table.resize (list.size(), 2);
258 uint32_t row = 0;
259 MetadataPtr field;
260 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
261 field = *it;
262 field->load_data (data);
263 table.attach (field->name_widget(), 0, 1, row, row + 1);
264 table.attach (field->edit_widget(), 1, 2, row, row + 1);
265 ++row;
269 void
270 SessionMetadataSetEditable::save_data ()
272 ARDOUR::SessionMetadata & data = _session->metadata();
273 for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
274 (*it)->save_data(data);
278 /* SessionMetadataSetImportable */
280 SessionMetadataSetImportable::SessionMetadataSetImportable (string const & name)
281 : SessionMetadataSet (name)
282 , session_list (list)
284 tree = Gtk::ListStore::create (tree_cols);
285 tree_view.set_model (tree);
287 Gtk::TreeView::Column * viewcol;
289 // Add import column
290 Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle());
291 import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed));
292 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render));
293 viewcol->add_attribute (import_render->property_active(), tree_cols.import);
294 tree_view.append_column (*viewcol);
296 // Add field name column
297 tree_view.append_column(_("Field"), tree_cols.field);
299 // Add values column with pango markup
300 Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText());
301 viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render));
302 viewcol->add_attribute (values_render->property_markup(), tree_cols.values);
303 tree_view.append_column (*viewcol);
305 select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all));
308 Gtk::Widget &
309 SessionMetadataSetImportable::get_tab_widget ()
311 tab_widget.set_text (name);
312 return tab_widget;
315 Gtk::Widget &
316 SessionMetadataSetImportable::get_select_all_widget ()
318 select_all_check.set_label (name);
319 return select_all_check;
322 void
323 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data)
325 if (!_session) {
326 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl;
327 return;
330 ARDOUR::SessionMetadata & session_data = _session->metadata();
332 MetadataPtr session_field;
333 MetadataPtr import_field;
334 DataList::iterator session_it;
335 DataList::iterator import_it;
337 // Copy list and load data to import
338 for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) {
339 session_field = *session_it;
340 session_field->load_data(session_data);
341 import_list.push_back (session_field->copy());
344 // Fill widget
345 session_it = session_list.begin();
346 import_it = import_list.begin();
347 while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same...
348 session_field = *session_it;
349 import_field = *import_it;
351 import_field->load_data(data); // hasn't been done yet
353 // Make string for values TODO get color from somewhere?
354 string values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
355 + "<span weight=\"bold\">" + import_field->value() + "</span>";
357 Gtk::TreeModel::iterator row_iter = tree->append();
358 Gtk::TreeModel::Row row = *row_iter;
360 row[tree_cols.field] = import_field->name();
361 row[tree_cols.values] = values;
362 row[tree_cols.import] = false;
363 row[tree_cols.data] = import_field;
365 ++session_it;
366 ++import_it;
370 void
371 SessionMetadataSetImportable::save_data ()
373 if (!_session) {
374 std::cerr << "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl;
375 return;
378 ARDOUR::SessionMetadata & session_data = _session->metadata();
380 Gtk::TreeModel::Children fields = tree->children();
381 Gtk::TreeModel::Children::iterator it;
382 for (it = fields.begin(); it != fields.end(); ++it) {
383 if ((*it)[tree_cols.import]) {
384 MetadataPtr field = (*it)[tree_cols.data];
385 field->save_data (session_data);
390 void
391 SessionMetadataSetImportable::select_all ()
393 select_all_check.set_inconsistent (false);
394 bool state = select_all_check.get_active();
396 Gtk::TreeModel::Children fields = tree->children();
397 Gtk::TreeModel::Children::iterator it;
398 for (it = fields.begin(); it != fields.end(); ++it) {
399 (*it)[tree_cols.import] = state;
403 void
404 SessionMetadataSetImportable::selection_changed (string const & path)
406 select_all_check.set_inconsistent (true);
408 Gtk::TreeModel::iterator iter = tree->get_iter (path);
409 bool value((*iter)[tree_cols.import]);
410 (*iter)[tree_cols.import] = !value;
413 /* SessionMetadataDialog */
415 template <typename DataSet>
416 SessionMetadataDialog<DataSet>::SessionMetadataDialog (string const & name) :
417 ArdourDialog (name, true)
419 cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
420 cancel_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::end_dialog));
421 save_button = add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
422 save_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::save_and_close));
425 template <typename DataSet>
426 void
427 SessionMetadataDialog<DataSet>::init_data ()
429 if (!_session) {
430 std::cerr << "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl;
431 return;
434 init_track_data ();
435 init_album_data ();
436 init_people_data ();
438 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
439 (*it)->set_session (_session);
441 notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget());
445 template <typename DataSet>
446 void
447 SessionMetadataDialog<DataSet>::load_extra_data (ARDOUR::SessionMetadata const & data)
449 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
450 (*it)->load_extra_data (data);
454 template <typename DataSet>
455 void
456 SessionMetadataDialog<DataSet>::save_data ()
458 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
459 (*it)->save_data ();
463 template <typename DataSet>
464 void
465 SessionMetadataDialog<DataSet>::save_and_close ()
467 save_data ();
468 end_dialog ();
471 template <typename DataSet>
472 void
473 SessionMetadataDialog<DataSet>::end_dialog ()
475 hide_all();
478 template <typename DataSet>
479 void
480 SessionMetadataDialog<DataSet>::warn_user (string const & string)
482 Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
483 msg.run();
486 template <typename DataSet>
487 boost::shared_ptr<std::list<Gtk::Widget *> >
488 SessionMetadataDialog<DataSet>::get_custom_widgets (WidgetFunc f)
490 WidgetListPtr list (new WidgetList);
491 for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it)
493 DataSet * set = dynamic_cast<DataSet *> (it->get());
494 list->push_back (& CALL_MEMBER_FN (*set, f) ());
497 return list;
500 template <typename DataSet>
501 void
502 SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
504 get_vbox()->pack_start (widget, true, true, 0);
507 template <typename DataSet>
508 void
509 SessionMetadataDialog<DataSet>::init_track_data ()
511 DataSetPtr data_set (new DataSet (_("Track")));
512 data_list.push_back (data_set);
514 MetadataPtr ptr;
516 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title")));
517 data_set->add_data_field (ptr);
519 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3));
520 data_set->add_data_field (ptr);
522 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle")));
523 data_set->add_data_field (ptr);
525 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping")));
526 data_set->add_data_field (ptr);
528 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist")));
529 data_set->add_data_field (ptr);
531 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre")));
532 data_set->add_data_field (ptr);
534 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment")));
535 data_set->add_data_field (ptr);
537 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright")));
538 data_set->add_data_field (ptr);
541 template <typename DataSet>
542 void
543 SessionMetadataDialog<DataSet>::init_album_data ()
545 DataSetPtr data_set (new DataSet (_("Album")));
546 data_list.push_back (data_set);
548 MetadataPtr ptr;
550 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album")));
551 data_set->add_data_field (ptr);
553 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4));
554 data_set->add_data_field (ptr);
556 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist")));
557 data_set->add_data_field (ptr);
559 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3));
560 data_set->add_data_field (ptr);
562 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle")));
563 data_set->add_data_field (ptr);
565 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2));
566 data_set->add_data_field (ptr);
568 ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2));
569 data_set->add_data_field (ptr);
571 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation")));
572 data_set->add_data_field (ptr);
574 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC")));
575 data_set->add_data_field (ptr);
578 template <typename DataSet>
579 void
580 SessionMetadataDialog<DataSet>::init_people_data ()
582 DataSetPtr data_set (new DataSet (_("People")));
583 data_list.push_back (data_set);
585 MetadataPtr ptr;
587 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist")));
588 data_set->add_data_field (ptr);
590 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer")));
591 data_set->add_data_field (ptr);
593 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor")));
594 data_set->add_data_field (ptr);
596 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer")));
597 data_set->add_data_field (ptr);
599 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger")));
600 data_set->add_data_field (ptr);
602 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer")));
603 data_set->add_data_field (ptr);
605 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer")));
606 data_set->add_data_field (ptr);
608 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer")));
609 data_set->add_data_field (ptr);
611 ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, _("Mixer")));
612 data_set->add_data_field (ptr);
615 /* SessionMetadataEditor */
617 SessionMetadataEditor::SessionMetadataEditor () :
618 SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit Session Metadata"))
623 SessionMetadataEditor::~SessionMetadataEditor ()
625 // Remove pages from notebook to get rid of gsignal runtime warnings
626 notebook.pages().clear();
629 void
630 SessionMetadataEditor::run ()
632 init_data ();
633 init_gui();
635 ArdourDialog::run();
638 void
639 SessionMetadataEditor::init_gui ()
641 add_widget (notebook);
643 show_all();
646 /* SessionMetadataImporter */
648 SessionMetadataImporter::SessionMetadataImporter () :
649 SessionMetadataDialog<SessionMetadataSetImportable> (_("Import session metadata"))
654 SessionMetadataImporter::~SessionMetadataImporter ()
656 // Remove pages from notebook to get rid of gsignal runtime warnings
657 notebook.pages().clear();
660 void
661 SessionMetadataImporter::run ()
663 if (!_session) {
664 std::cerr << "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl;
665 return;
668 /* Open session file selector */
670 Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN);
671 session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
672 session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
673 session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
675 Gtk::FileFilter session_filter;
676 session_filter.add_pattern ("*.ardour");
677 session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
678 session_selector.add_filter (session_filter);
679 session_selector.set_filter (session_filter);
681 int response = session_selector.run();
682 session_selector.hide ();
684 switch (response) {
685 case Gtk::RESPONSE_ACCEPT:
686 break;
687 default:
688 return;
691 string session_path = session_selector.get_filename();
692 string path, name;
693 bool isnew;
695 if (session_path.length() > 0) {
696 if (ARDOUR::find_session (session_path, path, name, isnew) != 0) {
697 return;
699 } else {
700 return;
703 /* We have a session: load the data and run dialog */
705 string filename = Glib::build_filename (path, name + ".ardour");
706 XMLTree session_tree;
707 if (!session_tree.read (filename)) {
708 warn_user (_("This session file could not be read!"));
709 return;
712 /* XXX GET VERSION FROM TREE */
713 int version = 3000;
715 XMLNode * node = session_tree.root()->child ("Metadata");
717 if (!node) {
718 warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
719 return;
722 ARDOUR::SessionMetadata data;
723 data.set_state (*node, version);
725 init_data ();
726 load_extra_data (data);
727 init_gui();
729 ArdourDialog::run();
732 void
733 SessionMetadataImporter::init_gui ()
735 // Select all from -widget
736 add_widget (selection_hbox);
737 selection_label.set_text (_("Import all from:"));
738 selection_hbox.pack_start (selection_label, false, false);
740 WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget);
741 for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) {
742 selection_hbox.pack_start (**it, false, false, 6);
745 add_widget (notebook);
747 show_all();