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