2 Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
21 /** @file src/config_dialog.cc
22 * @brief A dialogue to edit DCP-o-matic configuration.
25 #include "config_dialog.h"
27 #include "editable_list.h"
28 #include "filter_dialog.h"
29 #include "dir_picker_ctrl.h"
30 #include "file_picker_ctrl.h"
31 #include "isdcf_metadata_dialog.h"
32 #include "server_dialog.h"
33 #include "make_chain_dialog.h"
34 #include "email_dialog.h"
35 #include "name_format_editor.h"
36 #include "lib/config.h"
37 #include "lib/ratio.h"
38 #include "lib/filter.h"
39 #include "lib/dcp_content_type.h"
42 #include "lib/cross.h"
43 #include "lib/exceptions.h"
44 #include <dcp/locale_convert.h>
45 #include <dcp/exceptions.h>
46 #include <dcp/certificate_chain.h>
47 #include <wx/stdpaths.h>
48 #include <wx/preferences.h>
49 #include <wx/spinctrl.h>
50 #include <wx/filepicker.h>
52 #include <boost/filesystem.hpp>
53 #include <boost/foreach.hpp>
64 using boost::shared_ptr;
65 using boost::function;
66 using boost::optional;
67 using dcp::locale_convert;
72 Page (wxSize panel_size, int border)
75 , _panel_size (panel_size)
76 , _window_exists (false)
78 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
84 wxWindow* create_window (wxWindow* parent)
86 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
87 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
91 _window_exists = true;
94 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
103 virtual void config_changed () = 0;
104 virtual void setup () = 0;
106 void config_changed_wrapper ()
108 if (_window_exists) {
113 void window_destroyed ()
115 _window_exists = false;
119 boost::signals2::scoped_connection _config_connection;
123 class StockPage : public wxStockPreferencesPage, public Page
126 StockPage (Kind kind, wxSize panel_size, int border)
127 : wxStockPreferencesPage (kind)
128 , Page (panel_size, border)
131 wxWindow* CreateWindow (wxWindow* parent)
133 return create_window (parent);
137 class StandardPage : public wxPreferencesPage, public Page
140 StandardPage (wxSize panel_size, int border)
141 : Page (panel_size, border)
144 wxWindow* CreateWindow (wxWindow* parent)
146 return create_window (parent);
150 class GeneralPage : public StockPage
153 GeneralPage (wxSize panel_size, int border)
154 : StockPage (Kind_General, panel_size, border)
160 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
161 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
164 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
165 table->Add (_set_language, wxGBPosition (r, 0));
166 _language = new wxChoice (_panel, wxID_ANY);
167 vector<pair<string, string> > languages;
168 languages.push_back (make_pair ("Čeština", "cs_CZ"));
169 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
170 languages.push_back (make_pair ("Dansk", "da_DK"));
171 languages.push_back (make_pair ("Deutsch", "de_DE"));
172 languages.push_back (make_pair ("English", "en_GB"));
173 languages.push_back (make_pair ("Español", "es_ES"));
174 languages.push_back (make_pair ("Français", "fr_FR"));
175 languages.push_back (make_pair ("Italiano", "it_IT"));
176 languages.push_back (make_pair ("Nederlands", "nl_NL"));
177 languages.push_back (make_pair ("Русский", "ru_RU"));
178 languages.push_back (make_pair ("Polski", "pl_PL"));
179 languages.push_back (make_pair ("Português europeu", "pt_PT"));
180 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
181 languages.push_back (make_pair ("Svenska", "sv_SE"));
182 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
183 languages.push_back (make_pair ("українська мова", "uk_UA"));
184 checked_set (_language, languages);
185 table->Add (_language, wxGBPosition (r, 1));
188 wxStaticText* restart = add_label_to_sizer (
189 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
191 wxFont font = restart->GetFont();
192 font.SetStyle (wxFONTSTYLE_ITALIC);
193 font.SetPointSize (font.GetPointSize() - 1);
194 restart->SetFont (font);
197 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
198 _master_encoding_threads = new wxSpinCtrl (_panel);
199 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
202 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
203 _server_encoding_threads = new wxSpinCtrl (_panel);
204 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
207 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
208 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
209 table->Add (_cinemas_file, wxGBPosition (r, 1));
212 _preview_sound = new wxCheckBox (_panel, wxID_ANY, _("Play sound in the preview via"));
213 table->Add (_preview_sound, wxGBPosition (r, 0));
214 _preview_sound_output = new wxChoice (_panel, wxID_ANY);
215 table->Add (_preview_sound_output, wxGBPosition (r, 1));
218 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
219 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
220 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
224 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
225 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
228 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
229 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
232 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
233 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
236 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
237 bottom_table->AddGrowableCol (1, 1);
239 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
240 _issuer = new wxTextCtrl (_panel, wxID_ANY);
241 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
243 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
244 _creator = new wxTextCtrl (_panel, wxID_ANY);
245 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
247 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
250 RtAudio audio (DCPOMATIC_RTAUDIO_API);
251 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
252 RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
253 if (dev.probed && dev.outputChannels > 0) {
254 _preview_sound_output->Append (std_to_wx (dev.name));
258 _set_language->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::set_language_changed, this));
259 _language->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::language_changed, this));
260 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
261 _preview_sound->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::preview_sound_changed, this));
262 _preview_sound_output->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::preview_sound_output_changed, this));
264 _master_encoding_threads->SetRange (1, 128);
265 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::master_encoding_threads_changed, this));
266 _server_encoding_threads->SetRange (1, 128);
267 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::server_encoding_threads_changed, this));
269 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
270 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
272 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
273 _check_for_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_updates_changed, this));
274 _check_for_test_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
276 _issuer->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::issuer_changed, this));
277 _creator->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::creator_changed, this));
280 void config_changed ()
282 Config* config = Config::instance ();
284 checked_set (_set_language, static_cast<bool>(config->language()));
286 /* Backwards compatibility of config file */
288 map<string, string> compat_map;
289 compat_map["fr"] = "fr_FR";
290 compat_map["it"] = "it_IT";
291 compat_map["es"] = "es_ES";
292 compat_map["sv"] = "sv_SE";
293 compat_map["de"] = "de_DE";
294 compat_map["nl"] = "nl_NL";
295 compat_map["ru"] = "ru_RU";
296 compat_map["pl"] = "pl_PL";
297 compat_map["da"] = "da_DK";
298 compat_map["pt"] = "pt_PT";
299 compat_map["sk"] = "sk_SK";
300 compat_map["cs"] = "cs_CZ";
301 compat_map["uk"] = "uk_UA";
303 string lang = config->language().get_value_or ("en_GB");
304 if (compat_map.find (lang) != compat_map.end ()) {
305 lang = compat_map[lang];
308 checked_set (_language, lang);
310 checked_set (_master_encoding_threads, config->master_encoding_threads ());
311 checked_set (_server_encoding_threads, config->server_encoding_threads ());
312 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
313 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
315 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
316 checked_set (_check_for_updates, config->check_for_updates ());
317 checked_set (_check_for_test_updates, config->check_for_test_updates ());
318 checked_set (_issuer, config->dcp_issuer ());
319 checked_set (_creator, config->dcp_creator ());
320 checked_set (_cinemas_file, config->cinemas_file());
321 checked_set (_preview_sound, config->preview_sound());
323 optional<string> const current_so = get_preview_sound_output ();
324 string configured_so;
326 if (config->preview_sound_output()) {
327 configured_so = config->preview_sound_output().get();
329 /* No configured output means we should use the default */
330 RtAudio audio (DCPOMATIC_RTAUDIO_API);
331 configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
334 if (!current_so || *current_so != configured_so) {
335 /* Update _preview_sound_output with the configured value */
337 while (i < _preview_sound_output->GetCount()) {
338 if (_preview_sound_output->GetString(i) == std_to_wx(configured_so)) {
339 _preview_sound_output->SetSelection (i);
346 setup_sensitivity ();
349 /** @return Currently-selected preview sound output in the dialogue */
350 optional<string> get_preview_sound_output ()
352 int const sel = _preview_sound_output->GetSelection ();
353 if (sel == wxNOT_FOUND) {
354 return optional<string> ();
357 return wx_to_std (_preview_sound_output->GetString (sel));
360 void setup_sensitivity ()
362 _language->Enable (_set_language->GetValue ());
363 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
364 _preview_sound_output->Enable (_preview_sound->GetValue ());
367 void set_language_changed ()
369 setup_sensitivity ();
370 if (_set_language->GetValue ()) {
373 Config::instance()->unset_language ();
377 void language_changed ()
379 int const sel = _language->GetSelection ();
381 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
383 Config::instance()->unset_language ();
387 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
388 void analyse_ebur128_changed ()
390 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
394 void automatic_audio_analysis_changed ()
396 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
399 void check_for_updates_changed ()
401 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
404 void check_for_test_updates_changed ()
406 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
409 void master_encoding_threads_changed ()
411 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ());
414 void server_encoding_threads_changed ()
416 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ());
419 void issuer_changed ()
421 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
424 void creator_changed ()
426 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
429 void cinemas_file_changed ()
431 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
434 void preview_sound_changed ()
436 Config::instance()->set_preview_sound (_preview_sound->GetValue ());
439 void preview_sound_output_changed ()
441 RtAudio audio (DCPOMATIC_RTAUDIO_API);
442 optional<string> const so = get_preview_sound_output();
443 if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
444 Config::instance()->unset_preview_sound_output ();
446 Config::instance()->set_preview_sound_output (*so);
450 wxCheckBox* _set_language;
452 wxSpinCtrl* _master_encoding_threads;
453 wxSpinCtrl* _server_encoding_threads;
454 FilePickerCtrl* _cinemas_file;
455 wxCheckBox* _preview_sound;
456 wxChoice* _preview_sound_output;
457 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
458 wxCheckBox* _analyse_ebur128;
460 wxCheckBox* _automatic_audio_analysis;
461 wxCheckBox* _check_for_updates;
462 wxCheckBox* _check_for_test_updates;
464 wxTextCtrl* _creator;
467 class DefaultsPage : public StandardPage
470 DefaultsPage (wxSize panel_size, int border)
471 : StandardPage (panel_size, border)
474 wxString GetName () const
476 return _("Defaults");
480 wxBitmap GetLargeIcon () const
482 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
489 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
490 table->AddGrowableCol (1, 1);
491 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
494 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
495 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
496 _still_length = new wxSpinCtrl (_panel);
497 s->Add (_still_length);
498 add_label_to_sizer (s, _panel, _("s"), false);
502 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
503 #ifdef DCPOMATIC_USE_OWN_PICKER
504 _directory = new DirPickerCtrl (_panel);
506 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
508 table->Add (_directory, 1, wxEXPAND);
510 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
511 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
512 table->Add (_isdcf_metadata_button);
514 add_label_to_sizer (table, _panel, _("Default container"), true);
515 _container = new wxChoice (_panel, wxID_ANY);
516 table->Add (_container);
518 add_label_to_sizer (table, _panel, _("Default content type"), true);
519 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
520 table->Add (_dcp_content_type);
522 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
523 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
524 table->Add (_dcp_audio_channels);
527 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
528 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
529 _j2k_bandwidth = new wxSpinCtrl (_panel);
530 s->Add (_j2k_bandwidth);
531 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
536 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
537 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
538 _audio_delay = new wxSpinCtrl (_panel);
539 s->Add (_audio_delay);
540 add_label_to_sizer (s, _panel, _("ms"), false);
544 add_label_to_sizer (table, _panel, _("Default standard"), true);
545 _standard = new wxChoice (_panel, wxID_ANY);
546 table->Add (_standard);
548 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
549 #ifdef DCPOMATIC_USE_OWN_PICKER
550 _kdm_directory = new DirPickerCtrl (_panel);
552 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
554 table->Add (_kdm_directory, 1, wxEXPAND);
556 _still_length->SetRange (1, 3600);
557 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
559 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
560 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
562 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
564 vector<Ratio const *> ratios = Ratio::all ();
565 for (size_t i = 0; i < ratios.size(); ++i) {
566 _container->Append (std_to_wx (ratios[i]->nickname ()));
569 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
571 vector<DCPContentType const *> const ct = DCPContentType::all ();
572 for (size_t i = 0; i < ct.size(); ++i) {
573 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
576 setup_audio_channels_choice (_dcp_audio_channels, 2);
578 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
579 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
581 _j2k_bandwidth->SetRange (50, 250);
582 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
584 _audio_delay->SetRange (-1000, 1000);
585 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
587 _standard->Append (_("SMPTE"));
588 _standard->Append (_("Interop"));
589 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
592 void config_changed ()
594 Config* config = Config::instance ();
596 vector<Ratio const *> ratios = Ratio::all ();
597 for (size_t i = 0; i < ratios.size(); ++i) {
598 if (ratios[i] == config->default_container ()) {
599 _container->SetSelection (i);
603 vector<DCPContentType const *> const ct = DCPContentType::all ();
604 for (size_t i = 0; i < ct.size(); ++i) {
605 if (ct[i] == config->default_dcp_content_type ()) {
606 _dcp_content_type->SetSelection (i);
610 checked_set (_still_length, config->default_still_length ());
611 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
612 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
613 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
614 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
615 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
616 checked_set (_audio_delay, config->default_audio_delay ());
617 checked_set (_standard, config->default_interop() ? 1 : 0);
620 void j2k_bandwidth_changed ()
622 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
625 void audio_delay_changed ()
627 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
630 void dcp_audio_channels_changed ()
632 int const s = _dcp_audio_channels->GetSelection ();
633 if (s != wxNOT_FOUND) {
634 Config::instance()->set_default_dcp_audio_channels (
635 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
640 void directory_changed ()
642 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
645 void kdm_directory_changed ()
647 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
650 void edit_isdcf_metadata_clicked ()
652 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
654 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
658 void still_length_changed ()
660 Config::instance()->set_default_still_length (_still_length->GetValue ());
663 void container_changed ()
665 vector<Ratio const *> ratio = Ratio::all ();
666 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
669 void dcp_content_type_changed ()
671 vector<DCPContentType const *> ct = DCPContentType::all ();
672 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
675 void standard_changed ()
677 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
680 wxSpinCtrl* _j2k_bandwidth;
681 wxSpinCtrl* _audio_delay;
682 wxButton* _isdcf_metadata_button;
683 wxSpinCtrl* _still_length;
684 #ifdef DCPOMATIC_USE_OWN_PICKER
685 DirPickerCtrl* _directory;
686 DirPickerCtrl* _kdm_directory;
688 wxDirPickerCtrl* _directory;
689 wxDirPickerCtrl* _kdm_directory;
691 wxChoice* _container;
692 wxChoice* _dcp_content_type;
693 wxChoice* _dcp_audio_channels;
697 class EncodingServersPage : public StandardPage
700 EncodingServersPage (wxSize panel_size, int border)
701 : StandardPage (panel_size, border)
704 wxString GetName () const
710 wxBitmap GetLargeIcon () const
712 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
719 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
720 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
722 vector<string> columns;
723 columns.push_back (wx_to_std (_("IP address / host name")));
724 _servers_list = new EditableList<string, ServerDialog> (
727 boost::bind (&Config::servers, Config::instance()),
728 boost::bind (&Config::set_servers, Config::instance(), _1),
729 boost::bind (&EncodingServersPage::server_column, this, _1)
732 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
734 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
737 void config_changed ()
739 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
740 _servers_list->refresh ();
743 void use_any_servers_changed ()
745 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
748 string server_column (string s)
753 wxCheckBox* _use_any_servers;
754 EditableList<string, ServerDialog>* _servers_list;
757 class CertificateChainEditor : public wxPanel
760 CertificateChainEditor (
764 function<void (shared_ptr<dcp::CertificateChain>)> set,
765 function<shared_ptr<const dcp::CertificateChain> (void)> get
771 wxFont subheading_font (*wxNORMAL_FONT);
772 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
774 _sizer = new wxBoxSizer (wxVERTICAL);
777 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
778 m->SetFont (subheading_font);
779 _sizer->Add (m, 0, wxALL, border);
782 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
783 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
785 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
790 ip.SetText (_("Type"));
792 _certificates->InsertColumn (0, ip);
798 ip.SetText (_("Thumbprint"));
801 wxFont font = ip.GetFont ();
802 font.SetFamily (wxFONTFAMILY_TELETYPE);
805 _certificates->InsertColumn (1, ip);
808 certificates_sizer->Add (_certificates, 1, wxEXPAND);
811 wxSizer* s = new wxBoxSizer (wxVERTICAL);
812 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
813 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
814 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
815 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
816 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
817 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
818 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
821 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
822 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
825 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
826 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
827 wxFont font = _private_key->GetFont ();
828 font.SetFamily (wxFONTFAMILY_TELETYPE);
829 _private_key->SetFont (font);
830 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
831 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
832 table->Add (_load_private_key, wxGBPosition (r, 2));
833 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
834 table->Add (_export_private_key, wxGBPosition (r, 3));
837 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
838 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
839 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
840 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
843 _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this));
844 _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this));
845 _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this));
846 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
847 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
848 _remake_certificates->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remake_certificates, this));
849 _load_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::load_private_key, this));
850 _export_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_private_key, this));
852 SetSizerAndFit (_sizer);
855 void config_changed ()
857 _chain.reset (new dcp::CertificateChain (*_get().get ()));
859 update_certificate_list ();
860 update_private_key ();
861 update_sensitivity ();
864 void add_button (wxWindow* button)
866 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
871 void add_certificate ()
873 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
875 if (d->ShowModal() == wxID_OK) {
878 string const extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
879 if (!extra.empty ()) {
882 _("This file contains other certificates (or other data) after its first certificate. "
883 "Only the first certificate will be used.")
888 update_certificate_list ();
889 } catch (dcp::MiscError& e) {
890 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
896 update_sensitivity ();
899 void remove_certificate ()
901 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
906 _certificates->DeleteItem (i);
910 update_sensitivity ();
913 void export_certificate ()
915 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
920 wxFileDialog* d = new wxFileDialog (
921 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
922 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
925 dcp::CertificateChain::List all = _chain->root_to_leaf ();
926 dcp::CertificateChain::List::iterator j = all.begin ();
927 for (int k = 0; k < i; ++k) {
931 if (d->ShowModal () == wxID_OK) {
932 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
934 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
937 string const s = j->certificate (true);
938 fwrite (s.c_str(), 1, s.length(), f);
944 void update_certificate_list ()
946 _certificates->DeleteAllItems ();
948 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
949 BOOST_FOREACH (dcp::Certificate const & i, certs) {
952 _certificates->InsertItem (item);
953 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
956 _certificates->SetItem (n, 0, _("Root"));
957 } else if (n == (certs.size() - 1)) {
958 _certificates->SetItem (n, 0, _("Leaf"));
960 _certificates->SetItem (n, 0, _("Intermediate"));
967 void remake_certificates ()
969 shared_ptr<const dcp::CertificateChain> chain = _get ();
971 string subject_organization_name;
972 string subject_organizational_unit_name;
973 string root_common_name;
974 string intermediate_common_name;
975 string leaf_common_name;
977 dcp::CertificateChain::List all = chain->root_to_leaf ();
979 if (all.size() >= 1) {
981 subject_organization_name = chain->root().subject_organization_name ();
982 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
983 root_common_name = chain->root().subject_common_name ();
986 if (all.size() >= 2) {
988 leaf_common_name = chain->leaf().subject_common_name ();
991 if (all.size() >= 3) {
992 /* Have an intermediate */
993 dcp::CertificateChain::List::iterator i = all.begin ();
995 intermediate_common_name = i->subject_common_name ();
998 MakeChainDialog* d = new MakeChainDialog (
1000 subject_organization_name,
1001 subject_organizational_unit_name,
1003 intermediate_common_name,
1007 if (d->ShowModal () == wxID_OK) {
1009 new dcp::CertificateChain (
1012 d->organisational_unit (),
1013 d->root_common_name (),
1014 d->intermediate_common_name (),
1015 d->leaf_common_name ()
1020 update_certificate_list ();
1021 update_private_key ();
1027 void update_sensitivity ()
1029 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
1030 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
1033 void update_private_key ()
1035 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
1039 void load_private_key ()
1041 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
1043 if (d->ShowModal() == wxID_OK) {
1045 boost::filesystem::path p (wx_to_std (d->GetPath ()));
1046 if (boost::filesystem::file_size (p) > 8192) {
1049 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
1054 _chain->set_key (dcp::file_to_string (p));
1056 update_private_key ();
1057 } catch (dcp::MiscError& e) {
1058 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
1064 update_sensitivity ();
1067 void export_private_key ()
1069 optional<string> key = _chain->key ();
1074 wxFileDialog* d = new wxFileDialog (
1075 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1076 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1079 if (d->ShowModal () == wxID_OK) {
1080 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1082 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1085 string const s = _chain->key().get ();
1086 fwrite (s.c_str(), 1, s.length(), f);
1092 wxListCtrl* _certificates;
1093 wxButton* _add_certificate;
1094 wxButton* _export_certificate;
1095 wxButton* _remove_certificate;
1096 wxButton* _remake_certificates;
1097 wxStaticText* _private_key;
1098 wxButton* _load_private_key;
1099 wxButton* _export_private_key;
1101 wxBoxSizer* _button_sizer;
1102 shared_ptr<dcp::CertificateChain> _chain;
1103 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1104 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1107 class KeysPage : public StandardPage
1110 KeysPage (wxSize panel_size, int border)
1111 : StandardPage (panel_size, border)
1114 wxString GetName () const
1119 #ifdef DCPOMATIC_OSX
1120 wxBitmap GetLargeIcon () const
1122 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1130 _signer = new CertificateChainEditor (
1131 _panel, _("Signing DCPs and KDMs"), _border,
1132 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1133 boost::bind (&Config::signer_chain, Config::instance ())
1136 _panel->GetSizer()->Add (_signer);
1138 _decryption = new CertificateChainEditor (
1139 _panel, _("Decrypting DCPs"), _border,
1140 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1141 boost::bind (&Config::decryption_chain, Config::instance ())
1144 _panel->GetSizer()->Add (_decryption);
1146 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1147 _decryption->add_button (_export_decryption_certificate);
1148 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1149 _decryption->add_button (_export_decryption_chain);
1151 _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
1152 _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
1155 void export_decryption_certificate ()
1157 wxFileDialog* d = new wxFileDialog (
1158 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1159 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1162 if (d->ShowModal () == wxID_OK) {
1163 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1165 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1168 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1169 fwrite (s.c_str(), 1, s.length(), f);
1175 void export_decryption_chain ()
1177 wxFileDialog* d = new wxFileDialog (
1178 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1179 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1182 if (d->ShowModal () == wxID_OK) {
1183 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1185 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1188 string const s = Config::instance()->decryption_chain()->chain();
1189 fwrite (s.c_str(), 1, s.length(), f);
1195 void config_changed ()
1197 _signer->config_changed ();
1198 _decryption->config_changed ();
1201 CertificateChainEditor* _signer;
1202 CertificateChainEditor* _decryption;
1203 wxButton* _export_decryption_certificate;
1204 wxButton* _export_decryption_chain;
1207 class TMSPage : public StandardPage
1210 TMSPage (wxSize panel_size, int border)
1211 : StandardPage (panel_size, border)
1214 wxString GetName () const
1219 #ifdef DCPOMATIC_OSX
1220 wxBitmap GetLargeIcon () const
1222 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1229 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1230 table->AddGrowableCol (1, 1);
1231 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1233 add_label_to_sizer (table, _panel, _("Protocol"), true);
1234 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1235 table->Add (_tms_protocol, 1, wxEXPAND);
1237 add_label_to_sizer (table, _panel, _("IP address"), true);
1238 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1239 table->Add (_tms_ip, 1, wxEXPAND);
1241 add_label_to_sizer (table, _panel, _("Target path"), true);
1242 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1243 table->Add (_tms_path, 1, wxEXPAND);
1245 add_label_to_sizer (table, _panel, _("User name"), true);
1246 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1247 table->Add (_tms_user, 1, wxEXPAND);
1249 add_label_to_sizer (table, _panel, _("Password"), true);
1250 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1251 table->Add (_tms_password, 1, wxEXPAND);
1253 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1254 _tms_protocol->Append (_("FTP (for Dolby)"));
1256 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
1257 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
1258 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
1259 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
1260 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
1263 void config_changed ()
1265 Config* config = Config::instance ();
1267 checked_set (_tms_protocol, config->tms_protocol ());
1268 checked_set (_tms_ip, config->tms_ip ());
1269 checked_set (_tms_path, config->tms_path ());
1270 checked_set (_tms_user, config->tms_user ());
1271 checked_set (_tms_password, config->tms_password ());
1274 void tms_protocol_changed ()
1276 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1279 void tms_ip_changed ()
1281 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1284 void tms_path_changed ()
1286 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1289 void tms_user_changed ()
1291 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1294 void tms_password_changed ()
1296 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1299 wxChoice* _tms_protocol;
1300 wxTextCtrl* _tms_ip;
1301 wxTextCtrl* _tms_path;
1302 wxTextCtrl* _tms_user;
1303 wxTextCtrl* _tms_password;
1312 class KDMEmailPage : public StandardPage
1316 KDMEmailPage (wxSize panel_size, int border)
1317 #ifdef DCPOMATIC_OSX
1318 /* We have to force both width and height of this one */
1319 : StandardPage (wxSize (480, 128), border)
1321 : StandardPage (panel_size, border)
1325 wxString GetName () const
1327 return _("KDM Email");
1330 #ifdef DCPOMATIC_OSX
1331 wxBitmap GetLargeIcon () const
1333 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1340 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1341 table->AddGrowableCol (1, 1);
1342 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1344 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1346 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1347 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1348 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1349 add_label_to_sizer (s, _panel, _("port"), false);
1350 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1351 _mail_port->SetRange (0, 65535);
1352 s->Add (_mail_port);
1353 table->Add (s, 1, wxEXPAND | wxALL);
1356 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1357 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1358 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1360 add_label_to_sizer (table, _panel, _("Mail password"), true);
1361 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1362 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1364 add_label_to_sizer (table, _panel, _("Subject"), true);
1365 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1366 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1368 add_label_to_sizer (table, _panel, _("From address"), true);
1369 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1370 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1372 vector<string> columns;
1373 columns.push_back (wx_to_std (_("Address")));
1374 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1375 _kdm_cc = new EditableList<string, EmailDialog> (
1378 bind (&Config::kdm_cc, Config::instance()),
1379 bind (&Config::set_kdm_cc, Config::instance(), _1),
1382 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1384 add_label_to_sizer (table, _panel, _("BCC address"), true);
1385 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1386 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1388 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1389 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1391 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1392 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1396 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
1397 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
1398 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
1399 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
1400 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1401 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1402 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1403 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1404 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1407 void config_changed ()
1409 Config* config = Config::instance ();
1411 checked_set (_mail_server, config->mail_server ());
1412 checked_set (_mail_port, config->mail_port ());
1413 checked_set (_mail_user, config->mail_user ());
1414 checked_set (_mail_password, config->mail_password ());
1415 checked_set (_kdm_subject, config->kdm_subject ());
1416 checked_set (_kdm_from, config->kdm_from ());
1417 checked_set (_kdm_bcc, config->kdm_bcc ());
1418 checked_set (_kdm_email, Config::instance()->kdm_email ());
1421 void mail_server_changed ()
1423 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1426 void mail_port_changed ()
1428 Config::instance()->set_mail_port (_mail_port->GetValue ());
1431 void mail_user_changed ()
1433 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1436 void mail_password_changed ()
1438 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1441 void kdm_subject_changed ()
1443 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1446 void kdm_from_changed ()
1448 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1451 void kdm_bcc_changed ()
1453 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1456 void kdm_email_changed ()
1458 if (_kdm_email->GetValue().IsEmpty ()) {
1459 /* Sometimes we get sent an erroneous notification that the email
1460 is empty; I don't know why.
1464 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1467 void reset_kdm_email ()
1469 Config::instance()->reset_kdm_email ();
1470 checked_set (_kdm_email, Config::instance()->kdm_email ());
1473 wxTextCtrl* _mail_server;
1474 wxSpinCtrl* _mail_port;
1475 wxTextCtrl* _mail_user;
1476 wxTextCtrl* _mail_password;
1477 wxTextCtrl* _kdm_subject;
1478 wxTextCtrl* _kdm_from;
1479 EditableList<string, EmailDialog>* _kdm_cc;
1480 wxTextCtrl* _kdm_bcc;
1481 wxTextCtrl* _kdm_email;
1482 wxButton* _reset_kdm_email;
1485 /** @class AdvancedPage
1486 * @brief Advanced page of the preferences dialog.
1488 class AdvancedPage : public StockPage
1491 AdvancedPage (wxSize panel_size, int border)
1492 : StockPage (Kind_Advanced, panel_size, border)
1493 , _maximum_j2k_bandwidth (0)
1494 , _allow_any_dcp_frame_rate (0)
1495 , _only_servers_encode (0)
1500 , _log_debug_decode (0)
1501 , _log_debug_encode (0)
1502 , _log_debug_email (0)
1506 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1508 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1510 flags |= wxALIGN_RIGHT;
1513 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1514 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1519 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1520 table->AddGrowableCol (1, 1);
1521 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1524 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1525 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1526 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1527 s->Add (_maximum_j2k_bandwidth, 1);
1528 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1532 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1533 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1534 table->AddSpacer (0);
1536 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1537 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1538 table->AddSpacer (0);
1541 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1542 dcp::NameFormat::Map titles;
1543 titles['t'] = "type (cpl/pkl)";
1544 dcp::NameFormat::Map examples;
1545 examples['t'] = "cpl";
1546 _dcp_metadata_filename_format = new NameFormatEditor (
1547 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1549 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1553 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1554 dcp::NameFormat::Map titles;
1555 titles['t'] = "type (j2c/pcm/sub)";
1556 titles['r'] = "reel number";
1557 titles['n'] = "number of reels";
1558 titles['c'] = "content filename";
1559 dcp::NameFormat::Map examples;
1560 examples['t'] = "j2c";
1561 examples['r'] = "1";
1562 examples['n'] = "4";
1563 examples['c'] = "myfile.mp4";
1564 _dcp_asset_filename_format = new NameFormatEditor (
1565 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1567 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1571 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1572 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1573 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1574 t->Add (_log_general, 1, wxEXPAND | wxALL);
1575 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1576 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1577 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1578 t->Add (_log_error, 1, wxEXPAND | wxALL);
1579 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1580 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1581 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1582 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1583 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1584 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1585 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1586 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1587 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1588 table->Add (t, 0, wxALL, 6);
1591 #ifdef DCPOMATIC_WINDOWS
1592 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1593 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1594 table->AddSpacer (0);
1597 _maximum_j2k_bandwidth->SetRange (1, 1000);
1598 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1599 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1600 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1601 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1602 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1603 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1604 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1605 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1606 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1607 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1608 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1609 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1610 #ifdef DCPOMATIC_WINDOWS
1611 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1615 void config_changed ()
1617 Config* config = Config::instance ();
1619 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1620 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1621 checked_set (_only_servers_encode, config->only_servers_encode ());
1622 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1623 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1624 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1625 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1626 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1627 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1628 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1629 #ifdef DCPOMATIC_WINDOWS
1630 checked_set (_win32_console, config->win32_console());
1634 void maximum_j2k_bandwidth_changed ()
1636 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1639 void allow_any_dcp_frame_rate_changed ()
1641 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1644 void only_servers_encode_changed ()
1646 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1649 void dcp_metadata_filename_format_changed ()
1651 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1654 void dcp_asset_filename_format_changed ()
1656 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1662 if (_log_general->GetValue ()) {
1663 types |= LogEntry::TYPE_GENERAL;
1665 if (_log_warning->GetValue ()) {
1666 types |= LogEntry::TYPE_WARNING;
1668 if (_log_error->GetValue ()) {
1669 types |= LogEntry::TYPE_ERROR;
1671 if (_log_timing->GetValue ()) {
1672 types |= LogEntry::TYPE_TIMING;
1674 if (_log_debug_decode->GetValue ()) {
1675 types |= LogEntry::TYPE_DEBUG_DECODE;
1677 if (_log_debug_encode->GetValue ()) {
1678 types |= LogEntry::TYPE_DEBUG_ENCODE;
1680 if (_log_debug_email->GetValue ()) {
1681 types |= LogEntry::TYPE_DEBUG_EMAIL;
1683 Config::instance()->set_log_types (types);
1686 #ifdef DCPOMATIC_WINDOWS
1687 void win32_console_changed ()
1689 Config::instance()->set_win32_console (_win32_console->GetValue ());
1693 wxSpinCtrl* _maximum_j2k_bandwidth;
1694 wxCheckBox* _allow_any_dcp_frame_rate;
1695 wxCheckBox* _only_servers_encode;
1696 NameFormatEditor* _dcp_metadata_filename_format;
1697 NameFormatEditor* _dcp_asset_filename_format;
1698 wxCheckBox* _log_general;
1699 wxCheckBox* _log_warning;
1700 wxCheckBox* _log_error;
1701 wxCheckBox* _log_timing;
1702 wxCheckBox* _log_debug_decode;
1703 wxCheckBox* _log_debug_encode;
1704 wxCheckBox* _log_debug_email;
1705 #ifdef DCPOMATIC_WINDOWS
1706 wxCheckBox* _win32_console;
1710 wxPreferencesEditor*
1711 create_config_dialog ()
1713 wxPreferencesEditor* e = new wxPreferencesEditor ();
1715 #ifdef DCPOMATIC_OSX
1716 /* Width that we force some of the config panels to be on OSX so that
1717 the containing window doesn't shrink too much when we select those panels.
1718 This is obviously an unpleasant hack.
1720 wxSize ps = wxSize (520, -1);
1721 int const border = 16;
1723 wxSize ps = wxSize (-1, -1);
1724 int const border = 8;
1727 e->AddPage (new GeneralPage (ps, border));
1728 e->AddPage (new DefaultsPage (ps, border));
1729 e->AddPage (new EncodingServersPage (ps, border));
1730 e->AddPage (new KeysPage (ps, border));
1731 e->AddPage (new TMSPage (ps, border));
1732 e->AddPage (new KDMEmailPage (ps, border));
1733 e->AddPage (new AdvancedPage (ps, border));