2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "export_main_dialog.h"
23 #include <sigc++/signal.h>
25 #include <pbd/filesystem.h>
29 #include <ardour/export_handler.h>
30 #include <ardour/export_filename.h>
31 #include <ardour/export_format_specification.h>
32 #include <ardour/export_channel_configuration.h>
33 #include <ardour/export_preset.h>
37 using namespace ARDOUR;
40 ExportMainDialog::ExportMainDialog (PublicEditor & editor) :
41 ArdourDialog (_("Export")),
44 preset_label (_("Preset:"), Gtk::ALIGN_LEFT),
45 preset_save_button (Gtk::Stock::SAVE),
46 preset_remove_button (Gtk::Stock::REMOVE),
47 preset_new_button (Gtk::Stock::NEW),
51 warn_label ("", Gtk::ALIGN_LEFT),
52 list_files_label (_("<span color=\"#ffa755\">Some already existing files will be overwritten.</span>"), Gtk::ALIGN_RIGHT),
53 list_files_button (_("List files")),
55 timespan_label (_("Time Span"), Gtk::ALIGN_LEFT),
57 channels_label (_("Channels"), Gtk::ALIGN_LEFT)
61 get_vbox()->pack_start (preset_align, false, false, 0);
62 get_vbox()->pack_start (timespan_label, false, false, 0);
63 get_vbox()->pack_start (timespan_align, false, false, 0);
64 get_vbox()->pack_start (channels_label, false, false, 0);
65 get_vbox()->pack_start (channels_align, false, false, 0);
66 get_vbox()->pack_start (file_notebook, false, false, 0);
67 get_vbox()->pack_start (warn_container, true, true, 0);
68 get_vbox()->pack_start (progress_container, true, true, 0);
70 timespan_align.add (timespan_selector);
71 timespan_align.set_padding (0, 12, 18, 0);
73 channels_align.add (channel_selector);
74 channels_align.set_padding (0, 12, 18, 0);
76 /* Preset manipulation */
78 preset_list = Gtk::ListStore::create (preset_cols);
79 preset_entry.set_model (preset_list);
80 preset_entry.set_text_column (preset_cols.label);
82 preset_align.add (preset_hbox);
83 preset_align.set_padding (0, 12, 0, 0);
85 preset_hbox.pack_start (preset_label, false, false, 0);
86 preset_hbox.pack_start (preset_entry, true, true, 6);
87 preset_hbox.pack_start (preset_save_button, false, false, 0);
88 preset_hbox.pack_start (preset_remove_button, false, false, 6);
89 preset_hbox.pack_start (preset_new_button, false, false, 0);
91 preset_save_button.set_sensitive (false);
92 preset_remove_button.set_sensitive (false);
93 preset_new_button.set_sensitive (false);
95 preset_select_connection = preset_entry.signal_changed().connect (sigc::mem_fun (*this, &ExportMainDialog::select_preset));
96 preset_save_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::save_current_preset));
97 preset_new_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::save_current_preset));
98 preset_remove_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::remove_current_preset));
102 warn_container.pack_start (warn_hbox, true, true, 6);
103 warn_container.pack_end (list_files_hbox, false, false, 0);
105 warn_hbox.pack_start (warn_label, true, true, 16);
106 warn_label.set_use_markup (true);
108 list_files_hbox.pack_end (list_files_button, false, false, 6);
109 list_files_hbox.pack_end (list_files_label, false, false, 6);
110 list_files_label.set_use_markup (true);
112 list_files_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::show_conflicting_files));
114 /* Progress indicators */
116 progress_container.pack_start (progress_label, false, false, 6);
117 progress_container.pack_start (progress_bar, false, false, 6);
121 cancel_button = add_button (Gtk::Stock::CANCEL, RESPONSE_CANCEL);
122 rt_export_button = add_button (_("Realtime export"), RESPONSE_RT);
123 fast_export_button = add_button (_("Fast Export"), RESPONSE_FAST);
125 cancel_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::close_dialog));
126 rt_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::export_rt));
127 fast_export_button->signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::export_fw));
129 /* Bolding for labels */
131 Pango::AttrList bold;
132 Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD);
135 timespan_label.set_attributes (bold);
136 channels_label.set_attributes (bold);
140 show_all_children ();
141 progress_container.hide_all();
144 ExportMainDialog::~ExportMainDialog ()
149 ExportMainDialog::set_session (ARDOUR::Session* s)
153 /* Init handler and profile manager */
155 handler = session->get_export_handler ();
156 status = session->get_export_status ();
157 profile_manager.reset (new ExportProfileManager (*session));
159 /* Selection range */
161 TimeSelection const & time (editor.get_selection().time);
163 profile_manager->set_selection_range (time.front().start, time.front().end);
165 profile_manager->set_selection_range ();
168 /* Last notebook page */
170 new_file_button.add (*Gtk::manage (new Gtk::Image (::get_icon("add"))));
171 new_file_button.set_alignment (0, 0.5);
172 new_file_button.set_relief (Gtk::RELIEF_NONE);
174 new_file_hbox.pack_start (new_file_button, true, true);
175 file_notebook.append_page (new_file_dummy, new_file_hbox);
176 file_notebook.set_tab_label_packing (new_file_dummy, true, true, Gtk::PACK_START);
177 new_file_hbox.show_all_children ();
179 page_change_connection = file_notebook.signal_switch_page().connect (sigc::mem_fun (*this, &ExportMainDialog::handle_page_change));
180 new_file_button.signal_clicked().connect (sigc::mem_fun (*this, &ExportMainDialog::add_new_file_page));
184 profile_manager->load_profile ();
185 sync_with_manager ();
189 timespan_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings));
190 channel_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings));
191 status->Aborting.connect (sigc::mem_fun (*this, &ExportMainDialog::notify_errors));
197 ExportMainDialog::select_timespan (Glib::ustring id)
199 set_title ("Export Range");
200 timespan_selector.select_one_range (id);
204 ExportMainDialog::notify_errors ()
206 if (status->errors()) {
207 Glib::ustring txt = _("Export has been aborted due to an error!\nSee the Log for details.");
208 Gtk::MessageDialog msg (txt, false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
214 ExportMainDialog::close_dialog ()
216 if (status->running) {
226 ExportMainDialog::sync_with_manager ()
228 /* Clear pages from notebook
229 The page switch handling has to be disabled during removing all pages due to a gtk bug
232 page_change_connection.block();
233 while (file_notebook.get_n_pages() > 1) {
234 file_notebook.remove_page (0);
236 page_change_connection.block(false);
239 last_visible_page = 0;
243 preset_list->clear();
245 PresetList const & presets = profile_manager->get_presets();
246 Gtk::ListStore::iterator tree_it;
248 for (PresetList::const_iterator it = presets.begin(); it != presets.end(); ++it) {
249 tree_it = preset_list->append();
250 tree_it->set_value (preset_cols.preset, *it);
251 tree_it->set_value (preset_cols.label, Glib::ustring ((*it)->name()));
253 if (*it == current_preset) {
254 preset_select_connection.block (true);
255 preset_entry.set_active (tree_it);
256 preset_select_connection.block (false);
260 /* Timespan and channel config */
262 timespan_selector.set_state (profile_manager->get_timespans().front(), session);
263 channel_selector.set_state (profile_manager->get_channel_configs().front(), session);
267 ExportProfileManager::FormatStateList const & formats = profile_manager->get_formats ();
268 ExportProfileManager::FormatStateList::const_iterator format_it;
269 ExportProfileManager::FilenameStateList const & filenames = profile_manager->get_filenames ();
270 ExportProfileManager::FilenameStateList::const_iterator filename_it;
271 for (format_it = formats.begin(), filename_it = filenames.begin();
272 format_it != formats.end() && filename_it != filenames.end();
273 ++format_it, ++filename_it) {
274 add_file_page (*format_it, *filename_it);
277 file_notebook.set_current_page (0);
282 ExportMainDialog::update_warnings ()
287 warn_label.set_markup (warn_string);
289 list_files_hbox.hide ();
290 list_files_string = "";
292 fast_export_button->set_sensitive (true);
293 rt_export_button->set_sensitive (true);
295 /* Add new warnings */
297 boost::shared_ptr<ExportProfileManager::Warnings> warnings = profile_manager->get_warnings();
299 for (std::list<Glib::ustring>::iterator it = warnings->errors.begin(); it != warnings->errors.end(); ++it) {
303 for (std::list<Glib::ustring>::iterator it = warnings->warnings.begin(); it != warnings->warnings.end(); ++it) {
307 if (!warnings->conflicting_filenames.empty()) {
308 list_files_hbox.show ();
309 for (std::list<Glib::ustring>::iterator it = warnings->conflicting_filenames.begin(); it != warnings->conflicting_filenames.end(); ++it) {
310 ustring::size_type pos = it->find_last_of ("/");
311 list_files_string += "\n" + it->substr (0, pos + 1) + "<b>" + it->substr (pos + 1) + "</b>";
317 ExportMainDialog::show_conflicting_files ()
319 ArdourDialog dialog (_("Files that will be overwritten"), true);
321 Gtk::Label label ("", Gtk::ALIGN_LEFT);
322 label.set_use_markup (true);
323 label.set_markup (list_files_string);
325 dialog.get_vbox()->pack_start (label);
326 dialog.add_button (Gtk::Stock::OK, 0);
327 dialog.show_all_children ();
333 ExportMainDialog::export_rt ()
335 profile_manager->prepare_for_export ();
336 handler->do_export (true);
341 ExportMainDialog::export_fw ()
343 profile_manager->prepare_for_export ();
344 handler->do_export (false);
349 ExportMainDialog::show_progress ()
351 status->running = true;
353 cancel_button->set_label (_("Stop Export"));
354 rt_export_button->set_sensitive (false);
355 fast_export_button->set_sensitive (false);
357 progress_bar.set_fraction (0.0);
358 warn_container.hide_all();
359 progress_container.show ();
360 progress_container.show_all_children ();
361 progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportMainDialog::progress_timeout), 100);
363 gtk_main_iteration ();
364 while (status->running) {
365 if (gtk_events_pending()) {
366 gtk_main_iteration ();
374 ExportMainDialog::get_nth_format_name (uint32_t n)
377 if ((page = dynamic_cast<FilePage *> (file_notebook.get_nth_page (n - 1)))) {
378 return page->get_format_name();
384 ExportMainDialog::progress_timeout ()
386 switch (status->stage) {
388 progress_label.set_text ("");
390 case export_ReadTimespan:
391 progress_label.set_text (string_compose (_("Reading timespan %1 of %2"), status->timespan, status->total_timespans));
393 case export_PostProcess:
394 progress_label.set_text (string_compose (_("Processing file %2 of %3 (%1) from timespan %4 of %5"),
395 get_nth_format_name (status->format),
396 status->format, status->total_formats,
397 status->timespan, status->total_timespans));
400 progress_label.set_text (string_compose (_("Encoding file %2 of %3 (%1) from timespan %4 of %5"),
401 get_nth_format_name (status->format),
402 status->format, status->total_formats,
403 status->timespan, status->total_timespans));
407 progress_bar.set_fraction (status->progress);
412 ExportMainDialog::select_preset ()
414 Gtk::ListStore::iterator it = preset_entry.get_active ();
415 Glib::ustring text = preset_entry.get_entry()->get_text();
416 bool preset_name_exists = false;
418 for (PresetList::const_iterator it = profile_manager->get_presets().begin(); it != profile_manager->get_presets().end(); ++it) {
419 if (!(*it)->name().compare (text)) { preset_name_exists = true; }
422 if (preset_list->iter_is_valid (it)) {
424 previous_preset = current_preset = it->get_value (preset_cols.preset);
425 if (!profile_manager->load_preset (current_preset)) {
426 Gtk::MessageDialog dialog (_("The selected preset did not load successfully!\nPerhaps it references a format that has been removed?"),
427 false, Gtk::MESSAGE_WARNING);
430 sync_with_manager ();
432 /* Make an edit, so that signal changed will be emitted on re-selection */
434 preset_select_connection.block (true);
435 preset_entry.get_entry()->set_text ("");
436 preset_entry.get_entry()->set_text (text);
437 preset_select_connection.block (false);
439 } else { // Text has been edited
440 if (previous_preset && !text.compare (previous_preset->name())) {
442 current_preset = previous_preset;
445 current_preset.reset ();
446 profile_manager->load_preset (current_preset);
450 preset_save_button.set_sensitive (current_preset);
451 preset_remove_button.set_sensitive (current_preset);
452 preset_new_button.set_sensitive (!current_preset && !text.empty() && !preset_name_exists);
456 ExportMainDialog::save_current_preset ()
458 if (!profile_manager) { return; }
460 previous_preset = current_preset = profile_manager->save_preset (preset_entry.get_entry()->get_text());
461 sync_with_manager ();
462 select_preset (); // Update preset widget states
466 ExportMainDialog::remove_current_preset ()
468 if (!profile_manager) { return; }
470 profile_manager->remove_preset();
471 preset_entry.get_entry()->set_text ("");
472 sync_with_manager ();
475 ExportMainDialog::FilePage::FilePage (Session * s, ManagerPtr profile_manager, ExportMainDialog * parent, uint32_t number,
476 ExportProfileManager::FormatStatePtr format_state,
477 ExportProfileManager::FilenameStatePtr filename_state) :
478 format_state (format_state),
479 filename_state (filename_state),
480 profile_manager (profile_manager),
482 format_label (_("Format"), Gtk::ALIGN_LEFT),
483 filename_label (_("Location"), Gtk::ALIGN_LEFT),
486 set_border_width (12);
488 pack_start (format_label, false, false, 0);
489 pack_start (format_align, false, false, 0);
490 pack_start (filename_label, false, false, 0);
491 pack_start (filename_align, false, false, 0);
493 format_align.add (format_selector);
494 format_align.set_padding (6, 12, 18, 0);
496 filename_align.add (filename_selector);
497 filename_align.set_padding (0, 12, 18, 0);
499 Pango::AttrList bold;
500 Pango::Attribute b = Pango::Attribute::create_attr_weight (Pango::WEIGHT_BOLD);
503 format_label.set_attributes (bold);
504 filename_label.set_attributes (bold);
505 tab_label.set_attributes (bold);
508 format_selector.set_state (format_state, s);
509 filename_selector.set_state (filename_state, s);
513 tab_close_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*parent, &ExportMainDialog::remove_file_page), this));
515 profile_manager->FormatListChanged.connect (sigc::mem_fun (format_selector, &ExportFormatSelector::update_format_list));
517 format_selector.FormatEdited.connect (sigc::mem_fun (*this, &ExportMainDialog::FilePage::save_format_to_manager));
518 format_selector.FormatRemoved.connect (sigc::mem_fun (*profile_manager, &ExportProfileManager::remove_format_profile));
519 format_selector.NewFormat.connect (sigc::mem_fun (*profile_manager, &ExportProfileManager::get_new_format));
521 format_selector.CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::FilePage::update_tab_label));
522 filename_selector.CriticalSelectionChanged.connect (CriticalSelectionChanged.make_slot());
526 tab_close_button.add (*Gtk::manage (new Gtk::Image (::get_icon("close"))));
527 tab_close_alignment.add (tab_close_button);
528 tab_close_alignment.set (0.5, 0.5, 0, 0);
530 tab_widget.pack_start (tab_label, false, false, 3);
531 tab_widget.pack_end (tab_close_alignment, false, false, 0);
532 tab_widget.show_all_children ();
537 show_all_children ();
540 ExportMainDialog::FilePage::~FilePage ()
545 ExportMainDialog::FilePage::set_remove_sensitive (bool value)
547 tab_close_button.set_sensitive (value);
551 ExportMainDialog::FilePage::get_format_name () const
553 if (format_state && format_state->format) {
554 return format_state->format->name();
560 ExportMainDialog::FilePage::save_format_to_manager (FormatPtr format)
562 profile_manager->save_format_to_disk (format);
566 ExportMainDialog::FilePage::update_tab_label ()
568 tab_label.set_text (string_compose ("%1 %2", tab_number, get_format_name()));
569 CriticalSelectionChanged();
573 ExportMainDialog::add_new_file_page ()
576 if ((page = dynamic_cast<FilePage *> (file_notebook.get_nth_page (file_notebook.get_current_page())))) {
577 add_file_page (profile_manager->duplicate_format_state (page->get_format_state()),
578 profile_manager->duplicate_filename_state (page->get_filename_state()));
583 ExportMainDialog::add_file_page (ExportProfileManager::FormatStatePtr format_state, ExportProfileManager::FilenameStatePtr filename_state)
585 FilePage * page = Gtk::manage (new FilePage (session, profile_manager, this, page_counter, format_state, filename_state));
586 page->CriticalSelectionChanged.connect (sigc::mem_fun (*this, &ExportMainDialog::update_warnings));
587 file_notebook.insert_page (*page, page->get_tab_widget(), file_notebook.get_n_pages() - 1);
589 update_remove_file_page_sensitivity ();
590 file_notebook.show_all_children();
597 ExportMainDialog::remove_file_page (FilePage * page)
599 profile_manager->remove_format_state (page->get_format_state());
600 profile_manager->remove_filename_state (page->get_filename_state());
602 file_notebook.remove_page (*page);
603 update_remove_file_page_sensitivity ();
609 ExportMainDialog::update_remove_file_page_sensitivity ()
612 if ((page = dynamic_cast<FilePage *> (file_notebook.get_nth_page (0)))) {
613 if (file_notebook.get_n_pages() > 2) {
614 page->set_remove_sensitive (true);
616 page->set_remove_sensitive (false);
622 ExportMainDialog::handle_page_change (GtkNotebookPage*, uint page)
624 if (page + 1 == (uint32_t) file_notebook.get_n_pages()) {
625 file_notebook.set_current_page (last_visible_page);
627 last_visible_page = page;
632 ExportMainDialog::add_error (Glib::ustring const & text)
634 fast_export_button->set_sensitive (false);
635 rt_export_button->set_sensitive (false);
637 if (warn_string.empty()) {
638 warn_string = _("<span color=\"#ffa755\">Error: ") + text + "</span>";
640 warn_string = _("<span color=\"#ffa755\">Error: ") + text + "</span>\n" + warn_string;
643 warn_label.set_markup (warn_string);
647 ExportMainDialog::add_warning (Glib::ustring const & text)
649 if (warn_string.empty()) {
650 warn_string = _("<span color=\"#ffa755\">Warning: ") + text + "</span>";
652 warn_string = warn_string + _("\n<span color=\"#ffa755\">Warning: ") + text + "</span>";
655 warn_label.set_markup (warn_string);