OSC: add use groups to GUI
[ardour.git] / gtk2_ardour / session_metadata_dialog.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
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.
9
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.
14
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.
18 */
19
20 #include <sstream>
21 #include <gtkmm/filechooserdialog.h>
22 #include <gtkmm/messagedialog.h>
23 #include <gtkmm/stock.h>
24
25 #include "pbd/xml++.h"
26 #include "pbd/error.h"
27
28 #include "ardour/filename_extensions.h"
29 #include "ardour/session.h"
30 #include "ardour/session_utils.h"
31
32 #include "gtkmm2ext/utils.h"
33
34 #include "session_metadata_dialog.h"
35
36 #include "pbd/i18n.h"
37
38 using namespace std;
39 using namespace Glib;
40 using namespace PBD;
41
42 #define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))
43
44 /*** MetadataField ***/
45
46 MetadataField::MetadataField (string const & field_name) :
47   _name (field_name)
48 {
49 }
50
51 MetadataField::~MetadataField() { }
52
53 /* TextMetadataField */
54
55 TextMetadataField::TextMetadataField (Getter getter, Setter setter, string const & field_name, guint width ) :
56   MetadataField (field_name),
57   getter (getter),
58   setter (setter),
59   width (width)
60 {
61         entry = 0;
62         label = 0;
63         value_label = 0;
64 }
65
66 MetadataPtr
67 TextMetadataField::copy ()
68 {
69         return MetadataPtr (new TextMetadataField (getter, setter, _name, width));
70 }
71
72 void
73 TextMetadataField::save_data (ARDOUR::SessionMetadata & data) const
74 {
75         CALL_MEMBER_FN (data, setter) (_value);
76 }
77
78 void
79 TextMetadataField::load_data (ARDOUR::SessionMetadata const & data)
80 {
81         _value = CALL_MEMBER_FN (data, getter) ();
82         if (entry) {
83                 entry->set_text (_value);
84         }
85 }
86
87 Gtk::Widget &
88 TextMetadataField::name_widget ()
89 {
90         label = Gtk::manage (new Gtk::Label(_name + ':'));
91         label->set_alignment (1, 0.5);
92         return *label;
93 }
94
95 Gtk::Widget &
96 TextMetadataField::value_widget ()
97 {
98         value_label = Gtk::manage (new Gtk::Label(_value));
99         return *value_label;
100 }
101
102 Gtk::Widget &
103 TextMetadataField::edit_widget ()
104 {
105         entry = Gtk::manage (new Gtk::Entry());
106
107         entry->set_text (_value);
108         entry->set_width_chars (width);
109         entry->signal_changed().connect (sigc::mem_fun(*this, &TextMetadataField::update_value));
110
111         return *entry;
112 }
113
114 void
115 TextMetadataField::update_value ()
116 {
117         _value = entry->get_text ();
118 }
119
120 /* NumberMetadataField */
121
122 NumberMetadataField::NumberMetadataField (Getter getter, Setter setter, string const & field_name, guint numbers, guint width) :
123   MetadataField (field_name),
124   getter (getter),
125   setter (setter),
126   numbers (numbers),
127   width (width)
128 {
129         entry = 0;
130         label = 0;
131         value_label = 0;
132 }
133
134 MetadataPtr
135 NumberMetadataField::copy ()
136 {
137         return MetadataPtr (new NumberMetadataField (getter, setter, _name, numbers, width));
138 }
139
140 void
141 NumberMetadataField::save_data (ARDOUR::SessionMetadata & data) const
142 {
143         uint32_t number = str_to_uint (_value);
144         CALL_MEMBER_FN (data, setter) (number);
145 }
146
147 void
148 NumberMetadataField::load_data (ARDOUR::SessionMetadata const & data)
149 {
150         uint32_t number = CALL_MEMBER_FN (data, getter) ();
151         _value = uint_to_str (number);
152         if (entry) {
153                 entry->set_text (_value);
154         }
155 }
156
157 void
158 NumberMetadataField::update_value ()
159 {
160         // Accept only numbers that will fit into a uint32_t
161         uint32_t number = str_to_uint (entry->get_text());
162         _value = uint_to_str (number);
163         entry->set_text (_value);
164 }
165
166 Gtk::Widget &
167 NumberMetadataField::name_widget ()
168 {
169         label = Gtk::manage (new Gtk::Label(_name + ':'));
170         label->set_alignment (1, 0.5);
171         return *label;
172 }
173
174 Gtk::Widget &
175 NumberMetadataField::value_widget ()
176 {
177         value_label = Gtk::manage (new Gtk::Label(_value));
178         return *value_label;
179 }
180
181 Gtk::Widget &
182 NumberMetadataField::edit_widget ()
183 {
184         entry = Gtk::manage (new Gtk::Entry());
185
186         entry->set_text (_value);
187         entry->set_width_chars (width);
188         entry->set_max_length (numbers);
189         entry->signal_changed().connect (sigc::mem_fun(*this, &NumberMetadataField::update_value));
190
191         return *entry;
192 }
193
194 string
195 NumberMetadataField::uint_to_str (uint32_t i) const
196 {
197         std::ostringstream oss ("");
198         oss << i;
199         if (oss.str().compare("0")) {
200                 return oss.str();
201         } else {
202                 return "";
203         }
204 }
205
206 uint32_t
207 NumberMetadataField::str_to_uint (string const & str) const
208 {
209         string tmp (str);
210         string::size_type i;
211         while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
212                 tmp.erase (i, 1);
213         }
214
215         std::istringstream iss(tmp);
216         uint32_t result = 0;
217         iss >> result;
218         return result;
219 }
220
221
222
223 /* EAN13MetadataField */
224
225 EAN13MetadataField::EAN13MetadataField (Getter getter, Setter setter, string const & field_name, guint width) :
226   MetadataField (field_name),
227   getter (getter),
228   setter (setter),
229   width (width)
230 {
231         entry = 0;
232         label = 0;
233         value_label = 0;
234         status_label = Gtk::manage (new Gtk::Label (""));
235 }
236
237 MetadataPtr
238 EAN13MetadataField::copy ()
239 {
240         return MetadataPtr (new EAN13MetadataField (getter, setter, _name, width));
241 }
242
243 void
244 EAN13MetadataField::save_data (ARDOUR::SessionMetadata & data) const
245 {
246         CALL_MEMBER_FN (data, setter) (_value);
247 }
248
249 void
250 EAN13MetadataField::load_data (ARDOUR::SessionMetadata const & data)
251 {
252         _value = CALL_MEMBER_FN (data, getter) ();
253         if (entry) {
254                 entry->set_text (_value);
255         }
256         update_status ();
257 }
258
259 void
260 EAN13MetadataField::update_value ()
261 {
262         // Accept only numeric characters
263         _value = numeric_string (entry->get_text());
264         entry->set_text (_value);
265         update_status ();
266 }
267
268 void
269 EAN13MetadataField::update_status ()
270 {
271         int len = _value.length ();
272         if (len == 13) {
273                 // calculate EAN-13 modulo 10 check digit
274                 int sum = 0;
275                 const char *p = _value.c_str();
276                 for (int i = 0; i < 12; i++) {
277                         char c = p[i] - '0';
278                         if (i % 2) {
279                                 sum += c * 3;
280                         } else {
281                                 sum += c;
282                         }
283                 }
284                 sum %= 10;
285                 if (sum)
286                         sum = 10 - sum;
287
288                 if (sum == p[12] - '0') {
289                         status_label->set_markup (string_compose(
290                                                 "<span color=\"green\">%1: %2</span>",
291                                                 _("EAN Check digit OK"), sum));
292                 } else {
293                         status_label->set_markup (string_compose(
294                                                 "<span color=\"#ffa755\">%1: %2 (%3 %4)</span>",
295                                                 _("EAN Check digit error"), p[12] - '0', _("expected"), sum));
296                 }
297         } else if (len > 0) {
298                 status_label->set_markup (string_compose(
299                                         "<span color=\"#ffa755\">%1: %2 (&lt;13)</span>",
300                                         _("EAN Length error"), len));
301         } else {
302                 status_label->set_text("");
303         }
304 }
305
306 Gtk::Widget &
307 EAN13MetadataField::name_widget ()
308 {
309         label = Gtk::manage (new Gtk::Label(_name + ':'));
310         label->set_alignment (1, 0.5);
311         return *label;
312 }
313
314 Gtk::Widget &
315 EAN13MetadataField::value_widget ()
316 {
317         value_label = Gtk::manage (new Gtk::Label(_value));
318         return *value_label;
319 }
320
321 Gtk::Widget &
322 EAN13MetadataField::edit_widget ()
323 {
324         entry = Gtk::manage (new Gtk::Entry());
325
326         entry->set_text (_value);
327         entry->set_width_chars (width);
328         entry->set_max_length (13);
329         entry->signal_changed().connect (sigc::mem_fun(*this, &EAN13MetadataField::update_value));
330
331         return *entry;
332 }
333
334 string
335 EAN13MetadataField::numeric_string (string const & str) const
336 {
337         string tmp (str);
338         string::size_type i;
339         while ((i = tmp.find_first_not_of("1234567890")) != string::npos) {
340                 tmp.erase (i, 1);
341         }
342         return tmp;
343 }
344
345 /* SessionMetadataSet */
346
347 SessionMetadataSet::SessionMetadataSet (string const & name)
348   : name (name)
349 {
350 }
351
352 void
353 SessionMetadataSet::add_data_field (MetadataPtr field)
354 {
355         list.push_back (field);
356 }
357
358 /* SessionMetadataSetEditable */
359
360 SessionMetadataSetEditable::SessionMetadataSetEditable (string const & name)
361   : SessionMetadataSet (name)
362 {
363         table.set_row_spacings (6);
364         table.set_col_spacings (12);
365         table.set_homogeneous (false);
366         vbox.pack_start (table, false, false);
367         vbox.set_spacing (6);
368         vbox.set_border_width (6);
369 }
370
371 Gtk::Widget &
372 SessionMetadataSetEditable::get_tab_widget ()
373 {
374         tab_widget.set_text (name);
375         return tab_widget;
376 }
377
378 void
379 SessionMetadataSetEditable::set_session (ARDOUR::Session * s)
380 {
381         SessionHandlePtr::set_session (s);
382
383         if (!_session) {
384                 return;
385         }
386
387         ARDOUR::SessionMetadata const & data = *(ARDOUR::SessionMetadata::Metadata());
388
389         table.resize (list.size(), 2);
390         uint32_t row = 0;
391         MetadataPtr field;
392         for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
393                 field = *it;
394                 field->load_data (data);
395                 table.attach (field->name_widget(), 0, 1, row, row + 1, Gtk::FILL);
396                 table.attach (field->edit_widget(), 1, 2, row, row + 1);
397                 ++row;
398         }
399 }
400
401 void
402 SessionMetadataSetEditable::save_data ()
403 {
404         ARDOUR::SessionMetadata & data = *(ARDOUR::SessionMetadata::Metadata());
405         for (DataList::const_iterator it = list.begin(); it != list.end(); ++it) {
406                 (*it)->save_data(data);
407         }
408 }
409
410 /* SessionMetadataSetImportable */
411
412 SessionMetadataSetImportable::SessionMetadataSetImportable (string const & name)
413   : SessionMetadataSet (name)
414   , session_list (list)
415 {
416         tree = Gtk::ListStore::create (tree_cols);
417         tree_view.set_model (tree);
418
419         Gtk::TreeView::Column * viewcol;
420
421         // Add import column
422         Gtk::CellRendererToggle * import_render = Gtk::manage(new Gtk::CellRendererToggle());
423         import_render->signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::selection_changed));
424         viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Import"), *import_render));
425         viewcol->add_attribute (import_render->property_active(), tree_cols.import);
426         tree_view.append_column (*viewcol);
427
428         // Add field name column
429         tree_view.append_column(_("Field"), tree_cols.field);
430
431         // Add values column with pango markup
432         Gtk::CellRendererText * values_render = Gtk::manage(new Gtk::CellRendererText());
433         viewcol = Gtk::manage(new Gtk::TreeView::Column (_("Values (current value on top)"), *values_render));
434         viewcol->add_attribute (values_render->property_markup(), tree_cols.values);
435         tree_view.append_column (*viewcol);
436
437         select_all_check.signal_toggled().connect (sigc::mem_fun(*this, &SessionMetadataSetImportable::select_all));
438 }
439
440 Gtk::Widget &
441 SessionMetadataSetImportable::get_tab_widget ()
442 {
443         tab_widget.set_text (name);
444         return tab_widget;
445 }
446
447 Gtk::Widget &
448 SessionMetadataSetImportable::get_select_all_widget ()
449 {
450         select_all_check.set_label (name);
451         return select_all_check;
452 }
453
454 void
455 SessionMetadataSetImportable::load_extra_data (ARDOUR::SessionMetadata const & data)
456 {
457         if (!_session) {
458                 error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataSetImportable (in load_data)!") << endmsg;
459                 return;
460         }
461
462         ARDOUR::SessionMetadata const & session_data = *(ARDOUR::SessionMetadata::Metadata());
463
464         MetadataPtr session_field;
465         MetadataPtr import_field;
466         DataList::iterator session_it;
467         DataList::iterator import_it;
468
469         // Copy list and load data to import
470         for (session_it = session_list.begin(); session_it != session_list.end(); ++session_it) {
471                 session_field = *session_it;
472                 session_field->load_data(session_data);
473                 import_list.push_back (session_field->copy());
474         }
475
476         // Fill widget
477         session_it = session_list.begin();
478         import_it = import_list.begin();
479         while (session_it != session_list.end() && import_it != import_list.end()) { // _should_ be the same...
480                 session_field = *session_it;
481                 import_field = *import_it;
482
483                 import_field->load_data(data); // hasn't been done yet
484
485                 // Make string for values TODO get color from somewhere?
486                 string values = "<span weight=\"ultralight\" color=\"#777\">" + session_field->value() + "</span>\n"
487                         + "<span weight=\"bold\">" + import_field->value() + "</span>";
488
489                 Gtk::TreeModel::iterator row_iter = tree->append();
490                 Gtk::TreeModel::Row row = *row_iter;
491
492                 row[tree_cols.field] = import_field->name();
493                 row[tree_cols.values] = values;
494                 row[tree_cols.import] = false;
495                 row[tree_cols.data] = import_field;
496
497                 ++session_it;
498                 ++import_it;
499         }
500 }
501
502 void
503 SessionMetadataSetImportable::save_data ()
504 {
505         if (!_session) {
506                 error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataSetImportable (in import_data)!") << endmsg;
507                 return;
508         }
509
510         ARDOUR::SessionMetadata & session_data = *(ARDOUR::SessionMetadata::Metadata());
511
512         Gtk::TreeModel::Children fields = tree->children();
513         Gtk::TreeModel::Children::iterator it;
514         for (it = fields.begin(); it != fields.end(); ++it) {
515                 if ((*it)[tree_cols.import]) {
516                         MetadataPtr field = (*it)[tree_cols.data];
517                         field->save_data (session_data);
518                 }
519         }
520 }
521
522 void
523 SessionMetadataSetImportable::select_all ()
524 {
525         select_all_check.set_inconsistent (false);
526         bool state = select_all_check.get_active();
527
528         Gtk::TreeModel::Children fields = tree->children();
529         Gtk::TreeModel::Children::iterator it;
530         for (it = fields.begin(); it != fields.end(); ++it) {
531                 (*it)[tree_cols.import] = state;
532         }
533 }
534
535 void
536 SessionMetadataSetImportable::selection_changed (string const & path)
537 {
538         select_all_check.set_inconsistent (true);
539
540         Gtk::TreeModel::iterator iter = tree->get_iter (path);
541         bool value((*iter)[tree_cols.import]);
542         (*iter)[tree_cols.import] = !value;
543 }
544
545 /* SessionMetadataDialog */
546
547 template <typename DataSet>
548 SessionMetadataDialog<DataSet>::SessionMetadataDialog (string const & name) :
549   ArdourDialog (name, true)
550 {
551         cancel_button = add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
552         cancel_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::end_dialog));
553         save_button = add_button (Gtk::Stock::OK, Gtk::RESPONSE_ACCEPT);
554         save_button->signal_clicked().connect (sigc::mem_fun(*this, &SessionMetadataDialog::save_and_close));
555 }
556
557 template <typename DataSet>
558 void
559 SessionMetadataDialog<DataSet>::init_data ( bool skip_user )
560 {
561         if (!_session) {
562                 error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataDialog (in init_data)!") << endmsg;
563                 return;
564         }
565
566         if (!skip_user)
567                 init_user_data ();
568         init_track_data ();
569         init_album_data ();
570         init_people_data ();
571         init_school_data ();
572
573         for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
574                 (*it)->set_session (_session);
575
576                 notebook.append_page ((*it)->get_widget(), (*it)->get_tab_widget());
577         }
578 }
579
580 template <typename DataSet>
581 void
582 SessionMetadataDialog<DataSet>::load_extra_data (ARDOUR::SessionMetadata const & data)
583 {
584         for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
585                 (*it)->load_extra_data (data);
586         }
587 }
588
589 template <typename DataSet>
590 void
591 SessionMetadataDialog<DataSet>::save_data ()
592 {
593         for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it) {
594                 (*it)->save_data ();
595         }
596 }
597
598 template <typename DataSet>
599 void
600 SessionMetadataDialog<DataSet>::save_and_close ()
601 {
602         save_data ();
603         _session->set_dirty();
604         end_dialog ();
605 }
606
607 template <typename DataSet>
608 void
609 SessionMetadataDialog<DataSet>::end_dialog ()
610 {
611         hide_all();
612 }
613
614 template <typename DataSet>
615 void
616 SessionMetadataDialog<DataSet>::warn_user (string const & string)
617 {
618         Gtk::MessageDialog msg (string, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK, true);
619         msg.run();
620 }
621
622 template <typename DataSet>
623 boost::shared_ptr<std::list<Gtk::Widget *> >
624 SessionMetadataDialog<DataSet>::get_custom_widgets (WidgetFunc f)
625 {
626         WidgetListPtr list (new WidgetList);
627         for (DataSetList::iterator it = data_list.begin(); it != data_list.end(); ++it)
628         {
629                 DataSet * set = dynamic_cast<DataSet *> (it->get());
630                 list->push_back (& CALL_MEMBER_FN (*set, f) ());
631         }
632
633         return list;
634 }
635
636 template <typename DataSet>
637 void
638 SessionMetadataDialog<DataSet>::add_widget (Gtk::Widget & widget)
639 {
640         get_vbox()->pack_start (widget, true, true, 0);
641 }
642
643 template <typename DataSet>
644 void
645 SessionMetadataDialog<DataSet>::init_user_data ()
646 {
647         DataSetPtr data_set (new DataSet (_("User")));
648         data_list.push_back (data_set);
649
650         MetadataPtr ptr;
651
652         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_name, &ARDOUR::SessionMetadata::set_user_name, _("Name")));
653         data_set->add_data_field (ptr);
654
655         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_email, &ARDOUR::SessionMetadata::set_user_email, _("Email")));
656         data_set->add_data_field (ptr);
657
658         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::user_web, &ARDOUR::SessionMetadata::set_user_web, _("Web")));
659         data_set->add_data_field (ptr);
660
661         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::organization, &ARDOUR::SessionMetadata::set_organization, _("Organization")));
662         data_set->add_data_field (ptr);
663
664         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::country, &ARDOUR::SessionMetadata::set_country, _("Country")));
665         data_set->add_data_field (ptr);
666
667 }
668
669 template <typename DataSet>
670 void
671 SessionMetadataDialog<DataSet>::init_track_data ()
672 {
673         DataSetPtr data_set (new DataSet (_("Track")));
674         data_list.push_back (data_set);
675
676         MetadataPtr ptr;
677
678         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::title, &ARDOUR::SessionMetadata::set_title, _("Title")));
679         data_set->add_data_field (ptr);
680
681         ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::track_number, &ARDOUR::SessionMetadata::set_track_number, _("Track Number"), 3));
682         data_set->add_data_field (ptr);
683
684         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::subtitle, &ARDOUR::SessionMetadata::set_subtitle, _("Subtitle")));
685         data_set->add_data_field (ptr);
686
687         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::grouping, &ARDOUR::SessionMetadata::set_grouping, _("Grouping")));
688         data_set->add_data_field (ptr);
689
690         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::artist, &ARDOUR::SessionMetadata::set_artist, _("Artist")));
691         data_set->add_data_field (ptr);
692
693         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::genre, &ARDOUR::SessionMetadata::set_genre, _("Genre")));
694         data_set->add_data_field (ptr);
695
696         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::comment, &ARDOUR::SessionMetadata::set_comment, _("Comment")));
697         data_set->add_data_field (ptr);
698
699         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::copyright, &ARDOUR::SessionMetadata::set_copyright, _("Copyright")));
700         data_set->add_data_field (ptr);
701 }
702
703 template <typename DataSet>
704 void
705 SessionMetadataDialog<DataSet>::init_album_data ()
706 {
707         DataSetPtr data_set (new DataSet (_("Album")));
708         data_list.push_back (data_set);
709
710         MetadataPtr ptr;
711
712         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album, &ARDOUR::SessionMetadata::set_album, _("Album")));
713         data_set->add_data_field (ptr);
714
715         ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::year, &ARDOUR::SessionMetadata::set_year, _("Year"), 4));
716         data_set->add_data_field (ptr);
717
718         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::album_artist, &ARDOUR::SessionMetadata::set_album_artist, _("Album Artist")));
719         data_set->add_data_field (ptr);
720
721         ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_tracks, &ARDOUR::SessionMetadata::set_total_tracks, _("Total Tracks"), 3));
722         data_set->add_data_field (ptr);
723
724         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::disc_subtitle, &ARDOUR::SessionMetadata::set_disc_subtitle, _("Disc Subtitle")));
725         data_set->add_data_field (ptr);
726
727         ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::disc_number, &ARDOUR::SessionMetadata::set_disc_number, _("Disc Number"), 2));
728         data_set->add_data_field (ptr);
729
730         ptr = MetadataPtr (new NumberMetadataField (&ARDOUR::SessionMetadata::total_discs, &ARDOUR::SessionMetadata::set_total_discs, _("Total Discs"), 2));
731         data_set->add_data_field (ptr);
732
733         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::compilation, &ARDOUR::SessionMetadata::set_compilation, _("Compilation")));
734         data_set->add_data_field (ptr);
735
736         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::isrc, &ARDOUR::SessionMetadata::set_isrc, _("ISRC")));
737         data_set->add_data_field (ptr);
738
739         ptr = MetadataPtr (new EAN13MetadataField (&ARDOUR::SessionMetadata::barcode, &ARDOUR::SessionMetadata::set_barcode, _("EAN barcode")));
740         data_set->add_data_field (ptr);
741
742         // EAN13MetadataField is the only kind of MetadataField which has a status label.
743         EAN13MetadataField &emf = (EAN13MetadataField &) *ptr;
744         ((Gtk::VBox &) data_set->get_widget()).pack_end (*emf.status_label);
745         emf.update_status ();
746 }
747
748 template <typename DataSet>
749 void
750 SessionMetadataDialog<DataSet>::init_people_data ()
751 {
752         DataSetPtr data_set (new DataSet (_("People")));
753         data_list.push_back (data_set);
754
755         MetadataPtr ptr;
756
757         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::lyricist, &ARDOUR::SessionMetadata::set_lyricist, _("Lyricist")));
758         data_set->add_data_field (ptr);
759
760         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::composer, &ARDOUR::SessionMetadata::set_composer, _("Composer")));
761         data_set->add_data_field (ptr);
762
763         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::conductor, &ARDOUR::SessionMetadata::set_conductor, _("Conductor")));
764         data_set->add_data_field (ptr);
765
766         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::remixer, &ARDOUR::SessionMetadata::set_remixer, _("Remixer")));
767         data_set->add_data_field (ptr);
768
769         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::arranger, &ARDOUR::SessionMetadata::set_arranger, _("Arranger")));
770         data_set->add_data_field (ptr);
771
772         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::engineer, &ARDOUR::SessionMetadata::set_engineer, _("Engineer")));
773         data_set->add_data_field (ptr);
774
775         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::producer, &ARDOUR::SessionMetadata::set_producer, _("Producer")));
776         data_set->add_data_field (ptr);
777
778         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::dj_mixer, &ARDOUR::SessionMetadata::set_dj_mixer, _("DJ Mixer")));
779         data_set->add_data_field (ptr);
780
781         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::mixer, &ARDOUR::SessionMetadata::set_mixer, S_("Metadata|Mixer")));
782         data_set->add_data_field (ptr);
783 }
784
785 template <typename DataSet>
786 void
787 SessionMetadataDialog<DataSet>::init_school_data ()
788 {
789         DataSetPtr data_set (new DataSet (_("School")));
790         data_list.push_back (data_set);
791
792         MetadataPtr ptr;
793
794         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::instructor, &ARDOUR::SessionMetadata::set_instructor, _("Instructor")));
795         data_set->add_data_field (ptr);
796
797         ptr = MetadataPtr (new TextMetadataField (&ARDOUR::SessionMetadata::course, &ARDOUR::SessionMetadata::set_course, _("Course")));
798         data_set->add_data_field (ptr);
799
800 }
801
802 /* SessionMetadataEditor */
803
804 SessionMetadataEditor::SessionMetadataEditor () :
805   SessionMetadataDialog<SessionMetadataSetEditable> (_("Edit Session Metadata"))
806 {
807
808 }
809
810 SessionMetadataEditor::~SessionMetadataEditor ()
811 {
812         // Remove pages from notebook to get rid of gsignal runtime warnings
813         notebook.pages().clear();
814 }
815
816 void
817 SessionMetadataEditor::run ()
818 {
819         init_data ();
820         init_gui();
821
822         ArdourDialog::run();
823 }
824
825 void
826 SessionMetadataEditor::init_gui ()
827 {
828         add_widget (notebook);
829
830         show_all();
831 }
832
833 /* SessionMetadataImporter */
834
835 SessionMetadataImporter::SessionMetadataImporter () :
836   SessionMetadataDialog<SessionMetadataSetImportable> (_("Import session metadata"))
837 {
838
839 }
840
841 SessionMetadataImporter::~SessionMetadataImporter ()
842 {
843         // Remove pages from notebook to get rid of gsignal runtime warnings
844         notebook.pages().clear();
845 }
846
847 void
848 SessionMetadataImporter::run ()
849 {
850         if (!_session) {
851                 error << string_compose (_("programming error: %1"), "no session set for SessionMetaDataImporter (in run)!") << endmsg;
852                 return;
853         }
854
855         /* Open session file selector */
856
857         Gtk::FileChooserDialog session_selector(_("Choose session to import metadata from"), Gtk::FILE_CHOOSER_ACTION_OPEN);
858         session_selector.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
859         session_selector.add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT);
860         session_selector.set_default_response(Gtk::RESPONSE_ACCEPT);
861
862         Gtk::FileFilter session_filter;
863         session_filter.add_pattern (string_compose(X_("*%1"), ARDOUR::statefile_suffix));
864         session_filter.set_name (string_compose (_("%1 sessions"), PROGRAM_NAME));
865         session_selector.add_filter (session_filter);
866         session_selector.set_filter (session_filter);
867
868         int response = session_selector.run();
869         session_selector.hide ();
870
871         switch (response) {
872         case Gtk::RESPONSE_ACCEPT:
873                 break;
874         default:
875                 return;
876         }
877
878         string session_path = session_selector.get_filename();
879         string path, name;
880         bool isnew;
881
882         if (session_path.length() > 0) {
883                 if (ARDOUR::find_session (session_path, path, name, isnew) != 0) {
884                         return;
885                 }
886         } else {
887                 return;
888         }
889
890         /* We have a session: load the data and run dialog */
891
892         string filename = Glib::build_filename (path, name + ARDOUR::statefile_suffix);
893         XMLTree session_tree;
894         if (!session_tree.read (filename)) {
895                 warn_user (_("This session file could not be read!"));
896                 return;
897         }
898
899         /* XXX GET VERSION FROM TREE */
900         int version = 3000;
901
902         XMLNode * node = session_tree.root()->child ("Metadata");
903
904         if (!node) {
905                 warn_user (_("The session file didn't contain metadata!\nMaybe this is an old session format?"));
906                 return;
907         }
908
909         //create a temporary
910         ARDOUR::SessionMetadata data;
911         data.set_state (*node, version);
912         init_data ( true );  //skip user data here
913         load_extra_data (data);
914         init_gui();
915
916         ArdourDialog::run();
917 }
918
919 void
920 SessionMetadataImporter::init_gui ()
921 {
922         // Select all from -widget
923         add_widget (selection_hbox);
924         selection_label.set_text (_("Import all from:"));
925         selection_hbox.pack_start (selection_label, false, false);
926
927         WidgetListPtr list = get_custom_widgets (&SessionMetadataSetImportable::get_select_all_widget);
928         for (WidgetList::iterator it = list->begin(); it != list->end(); ++it) {
929                 selection_hbox.pack_start (**it, false, false, 6);
930         }
931
932         add_widget (notebook);
933
934         show_all();
935 }