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"
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
) :
222 SessionMetadataSet::add_data_field (MetadataPtr field
)
224 list
.push_back (field
);
227 /* SessionMetadataSetEditable */
229 SessionMetadataSetEditable::SessionMetadataSetEditable (ustring
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);
240 SessionMetadataSetEditable::get_tab_widget ()
242 tab_widget
.set_text (name
);
247 SessionMetadataSetEditable::set_session (ARDOUR::Session
* s
)
249 SessionHandlePtr::set_session (s
);
255 ARDOUR::SessionMetadata
const & data
= _session
->metadata();
257 table
.resize (list
.size(), 2);
260 for (DataList::const_iterator it
= list
.begin(); it
!= list
.end(); ++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);
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 (ustring
const & name
) :
281 SessionMetadataSet (name
),
284 tree
= Gtk::ListStore::create (tree_cols
);
285 tree_view
.set_model (tree
);
287 Gtk::TreeView::Column
* viewcol
;
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
));
309 SessionMetadataSetImportable::get_tab_widget ()
311 tab_widget
.set_text (name
);
316 SessionMetadataSetImportable::get_select_all_widget ()
318 select_all_check
.set_label (name
);
319 return select_all_check
;
323 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata
const & data
)
326 std::cerr
<< "Programming error: no session set for SessionMetaDataSetImportable (in load_data)!" << std::endl
;
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());
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 ustring 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
;
371 SessionMetadataSetImportable::save_data ()
374 std::cerr
<< "Programming error: no session set for SessionMetaDataSetImportable (in import_data)!" << std::endl
;
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
);
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
;
404 SessionMetadataSetImportable::selection_changed (ustring
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 (ustring
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
>
427 SessionMetadataDialog
<DataSet
>::init_data ()
430 std::cerr
<< "Programming error: no session set for SessionMetaDataDialog (in init_data)!" << std::endl
;
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
>
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
>
456 SessionMetadataDialog
<DataSet
>::save_data ()
458 for (DataSetList::iterator it
= data_list
.begin(); it
!= data_list
.end(); ++it
) {
463 template <typename DataSet
>
465 SessionMetadataDialog
<DataSet
>::save_and_close ()
471 template <typename DataSet
>
473 SessionMetadataDialog
<DataSet
>::end_dialog ()
478 template <typename DataSet
>
480 SessionMetadataDialog
<DataSet
>::warn_user (ustring
const & string
)
482 Gtk::MessageDialog
msg (string
, false, Gtk::MESSAGE_WARNING
, Gtk::BUTTONS_OK
, true);
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
) ());
500 template <typename DataSet
>
502 SessionMetadataDialog
<DataSet
>::add_widget (Gtk::Widget
& widget
)
504 get_vbox()->pack_start (widget
, true, true, 0);
507 template <typename DataSet
>
509 SessionMetadataDialog
<DataSet
>::init_track_data ()
511 DataSetPtr
data_set (new DataSet (_("Track")));
512 data_list
.push_back (data_set
);
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
>
543 SessionMetadataDialog
<DataSet
>::init_album_data ()
545 DataSetPtr
data_set (new DataSet (_("Album")));
546 data_list
.push_back (data_set
);
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
>
580 SessionMetadataDialog
<DataSet
>::init_people_data ()
582 DataSetPtr
data_set (new DataSet (_("People")));
583 data_list
.push_back (data_set
);
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();
630 SessionMetadataEditor::run ()
639 SessionMetadataEditor::init_gui ()
641 add_widget (notebook
);
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();
661 SessionMetadataImporter::run ()
664 std::cerr
<< "Programming error: no session set for SessionMetaDataImporter (in run)!" << std::endl
;
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 ();
685 case Gtk::RESPONSE_ACCEPT
:
691 string session_path
= session_selector
.get_filename();
695 if (session_path
.length() > 0) {
696 if (ARDOUR::find_session (session_path
, path
, name
, isnew
) != 0) {
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!"));
712 /* XXX GET VERSION FROM TREE */
715 XMLNode
* node
= session_tree
.root()->child ("Metadata");
718 warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
722 ARDOUR::SessionMetadata data
;
723 data
.set_state (*node
, version
);
726 load_extra_data (data
);
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
);