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, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
198 _num_local_encoding_threads = new wxSpinCtrl (_panel);
199 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
202 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
203 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
204 table->Add (_cinemas_file, wxGBPosition (r, 1));
207 _preview_sound = new wxCheckBox (_panel, wxID_ANY, _("Play sound in the preview via"));
208 table->Add (_preview_sound, wxGBPosition (r, 0));
209 _preview_sound_output = new wxChoice (_panel, wxID_ANY);
210 table->Add (_preview_sound_output, wxGBPosition (r, 1));
213 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
214 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
215 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
219 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
220 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
223 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
224 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
227 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
228 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
231 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
232 bottom_table->AddGrowableCol (1, 1);
234 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
235 _issuer = new wxTextCtrl (_panel, wxID_ANY);
236 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
238 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
239 _creator = new wxTextCtrl (_panel, wxID_ANY);
240 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
242 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
245 RtAudio audio (DCPOMATIC_RTAUDIO_API);
246 for (unsigned int i = 0; i < audio.getDeviceCount(); ++i) {
247 RtAudio::DeviceInfo dev = audio.getDeviceInfo (i);
248 if (dev.probed && dev.outputChannels > 0) {
249 _preview_sound_output->Append (std_to_wx (dev.name));
253 _set_language->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::set_language_changed, this));
254 _language->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::language_changed, this));
255 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
256 _preview_sound->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::preview_sound_changed, this));
257 _preview_sound_output->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::preview_sound_output_changed, this));
259 _num_local_encoding_threads->SetRange (1, 128);
260 _num_local_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
262 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
263 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
265 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
266 _check_for_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_updates_changed, this));
267 _check_for_test_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
269 _issuer->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::issuer_changed, this));
270 _creator->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::creator_changed, this));
273 void config_changed ()
275 Config* config = Config::instance ();
277 checked_set (_set_language, static_cast<bool>(config->language()));
279 /* Backwards compatibility of config file */
281 map<string, string> compat_map;
282 compat_map["fr"] = "fr_FR";
283 compat_map["it"] = "it_IT";
284 compat_map["es"] = "es_ES";
285 compat_map["sv"] = "sv_SE";
286 compat_map["de"] = "de_DE";
287 compat_map["nl"] = "nl_NL";
288 compat_map["ru"] = "ru_RU";
289 compat_map["pl"] = "pl_PL";
290 compat_map["da"] = "da_DK";
291 compat_map["pt"] = "pt_PT";
292 compat_map["sk"] = "sk_SK";
293 compat_map["cs"] = "cs_CZ";
294 compat_map["uk"] = "uk_UA";
296 string lang = config->language().get_value_or ("en_GB");
297 if (compat_map.find (lang) != compat_map.end ()) {
298 lang = compat_map[lang];
301 checked_set (_language, lang);
303 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
304 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
305 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
307 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
308 checked_set (_check_for_updates, config->check_for_updates ());
309 checked_set (_check_for_test_updates, config->check_for_test_updates ());
310 checked_set (_issuer, config->dcp_issuer ());
311 checked_set (_creator, config->dcp_creator ());
312 checked_set (_cinemas_file, config->cinemas_file());
313 checked_set (_preview_sound, config->preview_sound());
315 optional<string> const current_so = get_preview_sound_output ();
316 string configured_so;
318 if (config->preview_sound_output()) {
319 configured_so = config->preview_sound_output().get();
321 /* No configured output means we should use the default */
322 RtAudio audio (DCPOMATIC_RTAUDIO_API);
323 configured_so = audio.getDeviceInfo(audio.getDefaultOutputDevice()).name;
326 if (!current_so || *current_so != configured_so) {
327 /* Update _preview_sound_output with the configured value */
329 while (i < _preview_sound_output->GetCount()) {
330 if (_preview_sound_output->GetString(i) == std_to_wx(configured_so)) {
331 _preview_sound_output->SetSelection (i);
338 setup_sensitivity ();
341 /** @return Currently-selected preview sound output in the dialogue */
342 optional<string> get_preview_sound_output ()
344 int const sel = _preview_sound_output->GetSelection ();
345 if (sel == wxNOT_FOUND) {
346 return optional<string> ();
349 return wx_to_std (_preview_sound_output->GetString (sel));
352 void setup_sensitivity ()
354 _language->Enable (_set_language->GetValue ());
355 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
356 _preview_sound_output->Enable (_preview_sound->GetValue ());
359 void set_language_changed ()
361 setup_sensitivity ();
362 if (_set_language->GetValue ()) {
365 Config::instance()->unset_language ();
369 void language_changed ()
371 int const sel = _language->GetSelection ();
373 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
375 Config::instance()->unset_language ();
379 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
380 void analyse_ebur128_changed ()
382 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
386 void automatic_audio_analysis_changed ()
388 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
391 void check_for_updates_changed ()
393 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
396 void check_for_test_updates_changed ()
398 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
401 void num_local_encoding_threads_changed ()
403 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
406 void issuer_changed ()
408 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
411 void creator_changed ()
413 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
416 void cinemas_file_changed ()
418 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
421 void preview_sound_changed ()
423 Config::instance()->set_preview_sound (_preview_sound->GetValue ());
426 void preview_sound_output_changed ()
428 RtAudio audio (DCPOMATIC_RTAUDIO_API);
429 optional<string> const so = get_preview_sound_output();
430 if (!so || *so == audio.getDeviceInfo(audio.getDefaultOutputDevice()).name) {
431 Config::instance()->unset_preview_sound_output ();
433 Config::instance()->set_preview_sound_output (*so);
437 wxCheckBox* _set_language;
439 wxSpinCtrl* _num_local_encoding_threads;
440 FilePickerCtrl* _cinemas_file;
441 wxCheckBox* _preview_sound;
442 wxChoice* _preview_sound_output;
443 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
444 wxCheckBox* _analyse_ebur128;
446 wxCheckBox* _automatic_audio_analysis;
447 wxCheckBox* _check_for_updates;
448 wxCheckBox* _check_for_test_updates;
450 wxTextCtrl* _creator;
453 class DefaultsPage : public StandardPage
456 DefaultsPage (wxSize panel_size, int border)
457 : StandardPage (panel_size, border)
460 wxString GetName () const
462 return _("Defaults");
466 wxBitmap GetLargeIcon () const
468 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
475 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
476 table->AddGrowableCol (1, 1);
477 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
480 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
481 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
482 _still_length = new wxSpinCtrl (_panel);
483 s->Add (_still_length);
484 add_label_to_sizer (s, _panel, _("s"), false);
488 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
489 #ifdef DCPOMATIC_USE_OWN_PICKER
490 _directory = new DirPickerCtrl (_panel);
492 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
494 table->Add (_directory, 1, wxEXPAND);
496 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
497 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
498 table->Add (_isdcf_metadata_button);
500 add_label_to_sizer (table, _panel, _("Default container"), true);
501 _container = new wxChoice (_panel, wxID_ANY);
502 table->Add (_container);
504 add_label_to_sizer (table, _panel, _("Default content type"), true);
505 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
506 table->Add (_dcp_content_type);
508 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
509 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
510 table->Add (_dcp_audio_channels);
513 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
514 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
515 _j2k_bandwidth = new wxSpinCtrl (_panel);
516 s->Add (_j2k_bandwidth);
517 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
522 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
523 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
524 _audio_delay = new wxSpinCtrl (_panel);
525 s->Add (_audio_delay);
526 add_label_to_sizer (s, _panel, _("ms"), false);
530 add_label_to_sizer (table, _panel, _("Default standard"), true);
531 _standard = new wxChoice (_panel, wxID_ANY);
532 table->Add (_standard);
534 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
535 #ifdef DCPOMATIC_USE_OWN_PICKER
536 _kdm_directory = new DirPickerCtrl (_panel);
538 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
540 table->Add (_kdm_directory, 1, wxEXPAND);
542 _still_length->SetRange (1, 3600);
543 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
545 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
546 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
548 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
550 vector<Ratio const *> ratios = Ratio::all ();
551 for (size_t i = 0; i < ratios.size(); ++i) {
552 _container->Append (std_to_wx (ratios[i]->nickname ()));
555 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
557 vector<DCPContentType const *> const ct = DCPContentType::all ();
558 for (size_t i = 0; i < ct.size(); ++i) {
559 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
562 setup_audio_channels_choice (_dcp_audio_channels, 2);
564 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
565 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
567 _j2k_bandwidth->SetRange (50, 250);
568 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
570 _audio_delay->SetRange (-1000, 1000);
571 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
573 _standard->Append (_("SMPTE"));
574 _standard->Append (_("Interop"));
575 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
578 void config_changed ()
580 Config* config = Config::instance ();
582 vector<Ratio const *> ratios = Ratio::all ();
583 for (size_t i = 0; i < ratios.size(); ++i) {
584 if (ratios[i] == config->default_container ()) {
585 _container->SetSelection (i);
589 vector<DCPContentType const *> const ct = DCPContentType::all ();
590 for (size_t i = 0; i < ct.size(); ++i) {
591 if (ct[i] == config->default_dcp_content_type ()) {
592 _dcp_content_type->SetSelection (i);
596 checked_set (_still_length, config->default_still_length ());
597 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
598 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
599 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
600 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
601 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
602 checked_set (_audio_delay, config->default_audio_delay ());
603 checked_set (_standard, config->default_interop() ? 1 : 0);
606 void j2k_bandwidth_changed ()
608 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
611 void audio_delay_changed ()
613 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
616 void dcp_audio_channels_changed ()
618 int const s = _dcp_audio_channels->GetSelection ();
619 if (s != wxNOT_FOUND) {
620 Config::instance()->set_default_dcp_audio_channels (
621 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
626 void directory_changed ()
628 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
631 void kdm_directory_changed ()
633 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
636 void edit_isdcf_metadata_clicked ()
638 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
640 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
644 void still_length_changed ()
646 Config::instance()->set_default_still_length (_still_length->GetValue ());
649 void container_changed ()
651 vector<Ratio const *> ratio = Ratio::all ();
652 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
655 void dcp_content_type_changed ()
657 vector<DCPContentType const *> ct = DCPContentType::all ();
658 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
661 void standard_changed ()
663 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
666 wxSpinCtrl* _j2k_bandwidth;
667 wxSpinCtrl* _audio_delay;
668 wxButton* _isdcf_metadata_button;
669 wxSpinCtrl* _still_length;
670 #ifdef DCPOMATIC_USE_OWN_PICKER
671 DirPickerCtrl* _directory;
672 DirPickerCtrl* _kdm_directory;
674 wxDirPickerCtrl* _directory;
675 wxDirPickerCtrl* _kdm_directory;
677 wxChoice* _container;
678 wxChoice* _dcp_content_type;
679 wxChoice* _dcp_audio_channels;
683 class EncodingServersPage : public StandardPage
686 EncodingServersPage (wxSize panel_size, int border)
687 : StandardPage (panel_size, border)
690 wxString GetName () const
696 wxBitmap GetLargeIcon () const
698 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
705 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
706 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
708 vector<string> columns;
709 columns.push_back (wx_to_std (_("IP address / host name")));
710 _servers_list = new EditableList<string, ServerDialog> (
713 boost::bind (&Config::servers, Config::instance()),
714 boost::bind (&Config::set_servers, Config::instance(), _1),
715 boost::bind (&EncodingServersPage::server_column, this, _1)
718 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
720 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
723 void config_changed ()
725 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
726 _servers_list->refresh ();
729 void use_any_servers_changed ()
731 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
734 string server_column (string s)
739 wxCheckBox* _use_any_servers;
740 EditableList<string, ServerDialog>* _servers_list;
743 class CertificateChainEditor : public wxPanel
746 CertificateChainEditor (
750 function<void (shared_ptr<dcp::CertificateChain>)> set,
751 function<shared_ptr<const dcp::CertificateChain> (void)> get
757 wxFont subheading_font (*wxNORMAL_FONT);
758 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
760 _sizer = new wxBoxSizer (wxVERTICAL);
763 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
764 m->SetFont (subheading_font);
765 _sizer->Add (m, 0, wxALL, border);
768 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
769 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
771 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
776 ip.SetText (_("Type"));
778 _certificates->InsertColumn (0, ip);
784 ip.SetText (_("Thumbprint"));
787 wxFont font = ip.GetFont ();
788 font.SetFamily (wxFONTFAMILY_TELETYPE);
791 _certificates->InsertColumn (1, ip);
794 certificates_sizer->Add (_certificates, 1, wxEXPAND);
797 wxSizer* s = new wxBoxSizer (wxVERTICAL);
798 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
799 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
800 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
801 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
802 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
803 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
804 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
807 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
808 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
811 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
812 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
813 wxFont font = _private_key->GetFont ();
814 font.SetFamily (wxFONTFAMILY_TELETYPE);
815 _private_key->SetFont (font);
816 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
817 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
818 table->Add (_load_private_key, wxGBPosition (r, 2));
819 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
820 table->Add (_export_private_key, wxGBPosition (r, 3));
823 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
824 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
825 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
826 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
829 _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this));
830 _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this));
831 _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this));
832 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
833 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
834 _remake_certificates->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remake_certificates, this));
835 _load_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::load_private_key, this));
836 _export_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_private_key, this));
838 SetSizerAndFit (_sizer);
841 void config_changed ()
843 _chain.reset (new dcp::CertificateChain (*_get().get ()));
845 update_certificate_list ();
846 update_private_key ();
847 update_sensitivity ();
850 void add_button (wxWindow* button)
852 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
857 void add_certificate ()
859 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
861 if (d->ShowModal() == wxID_OK) {
864 string const extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
865 if (!extra.empty ()) {
868 _("This file contains other certificates (or other data) after its first certificate. "
869 "Only the first certificate will be used.")
874 update_certificate_list ();
875 } catch (dcp::MiscError& e) {
876 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
882 update_sensitivity ();
885 void remove_certificate ()
887 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
892 _certificates->DeleteItem (i);
896 update_sensitivity ();
899 void export_certificate ()
901 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
906 wxFileDialog* d = new wxFileDialog (
907 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
908 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
911 dcp::CertificateChain::List all = _chain->root_to_leaf ();
912 dcp::CertificateChain::List::iterator j = all.begin ();
913 for (int k = 0; k < i; ++k) {
917 if (d->ShowModal () == wxID_OK) {
918 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
920 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
923 string const s = j->certificate (true);
924 fwrite (s.c_str(), 1, s.length(), f);
930 void update_certificate_list ()
932 _certificates->DeleteAllItems ();
934 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
935 BOOST_FOREACH (dcp::Certificate const & i, certs) {
938 _certificates->InsertItem (item);
939 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
942 _certificates->SetItem (n, 0, _("Root"));
943 } else if (n == (certs.size() - 1)) {
944 _certificates->SetItem (n, 0, _("Leaf"));
946 _certificates->SetItem (n, 0, _("Intermediate"));
953 void remake_certificates ()
955 shared_ptr<const dcp::CertificateChain> chain = _get ();
957 string subject_organization_name;
958 string subject_organizational_unit_name;
959 string root_common_name;
960 string intermediate_common_name;
961 string leaf_common_name;
963 dcp::CertificateChain::List all = chain->root_to_leaf ();
965 if (all.size() >= 1) {
967 subject_organization_name = chain->root().subject_organization_name ();
968 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
969 root_common_name = chain->root().subject_common_name ();
972 if (all.size() >= 2) {
974 leaf_common_name = chain->leaf().subject_common_name ();
977 if (all.size() >= 3) {
978 /* Have an intermediate */
979 dcp::CertificateChain::List::iterator i = all.begin ();
981 intermediate_common_name = i->subject_common_name ();
984 MakeChainDialog* d = new MakeChainDialog (
986 subject_organization_name,
987 subject_organizational_unit_name,
989 intermediate_common_name,
993 if (d->ShowModal () == wxID_OK) {
995 new dcp::CertificateChain (
998 d->organisational_unit (),
999 d->root_common_name (),
1000 d->intermediate_common_name (),
1001 d->leaf_common_name ()
1006 update_certificate_list ();
1007 update_private_key ();
1013 void update_sensitivity ()
1015 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
1016 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
1019 void update_private_key ()
1021 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
1025 void load_private_key ()
1027 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
1029 if (d->ShowModal() == wxID_OK) {
1031 boost::filesystem::path p (wx_to_std (d->GetPath ()));
1032 if (boost::filesystem::file_size (p) > 8192) {
1035 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
1040 _chain->set_key (dcp::file_to_string (p));
1042 update_private_key ();
1043 } catch (dcp::MiscError& e) {
1044 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
1050 update_sensitivity ();
1053 void export_private_key ()
1055 optional<string> key = _chain->key ();
1060 wxFileDialog* d = new wxFileDialog (
1061 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1062 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1065 if (d->ShowModal () == wxID_OK) {
1066 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1068 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1071 string const s = _chain->key().get ();
1072 fwrite (s.c_str(), 1, s.length(), f);
1078 wxListCtrl* _certificates;
1079 wxButton* _add_certificate;
1080 wxButton* _export_certificate;
1081 wxButton* _remove_certificate;
1082 wxButton* _remake_certificates;
1083 wxStaticText* _private_key;
1084 wxButton* _load_private_key;
1085 wxButton* _export_private_key;
1087 wxBoxSizer* _button_sizer;
1088 shared_ptr<dcp::CertificateChain> _chain;
1089 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1090 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1093 class KeysPage : public StandardPage
1096 KeysPage (wxSize panel_size, int border)
1097 : StandardPage (panel_size, border)
1100 wxString GetName () const
1105 #ifdef DCPOMATIC_OSX
1106 wxBitmap GetLargeIcon () const
1108 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1116 _signer = new CertificateChainEditor (
1117 _panel, _("Signing DCPs and KDMs"), _border,
1118 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1119 boost::bind (&Config::signer_chain, Config::instance ())
1122 _panel->GetSizer()->Add (_signer);
1124 _decryption = new CertificateChainEditor (
1125 _panel, _("Decrypting DCPs"), _border,
1126 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1127 boost::bind (&Config::decryption_chain, Config::instance ())
1130 _panel->GetSizer()->Add (_decryption);
1132 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1133 _decryption->add_button (_export_decryption_certificate);
1134 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1135 _decryption->add_button (_export_decryption_chain);
1137 _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
1138 _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
1141 void export_decryption_certificate ()
1143 wxFileDialog* d = new wxFileDialog (
1144 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1145 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1148 if (d->ShowModal () == wxID_OK) {
1149 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1151 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1154 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1155 fwrite (s.c_str(), 1, s.length(), f);
1161 void export_decryption_chain ()
1163 wxFileDialog* d = new wxFileDialog (
1164 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1165 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1168 if (d->ShowModal () == wxID_OK) {
1169 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1171 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1174 string const s = Config::instance()->decryption_chain()->chain();
1175 fwrite (s.c_str(), 1, s.length(), f);
1181 void config_changed ()
1183 _signer->config_changed ();
1184 _decryption->config_changed ();
1187 CertificateChainEditor* _signer;
1188 CertificateChainEditor* _decryption;
1189 wxButton* _export_decryption_certificate;
1190 wxButton* _export_decryption_chain;
1193 class TMSPage : public StandardPage
1196 TMSPage (wxSize panel_size, int border)
1197 : StandardPage (panel_size, border)
1200 wxString GetName () const
1205 #ifdef DCPOMATIC_OSX
1206 wxBitmap GetLargeIcon () const
1208 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1215 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1216 table->AddGrowableCol (1, 1);
1217 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1219 add_label_to_sizer (table, _panel, _("Protocol"), true);
1220 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1221 table->Add (_tms_protocol, 1, wxEXPAND);
1223 add_label_to_sizer (table, _panel, _("IP address"), true);
1224 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1225 table->Add (_tms_ip, 1, wxEXPAND);
1227 add_label_to_sizer (table, _panel, _("Target path"), true);
1228 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1229 table->Add (_tms_path, 1, wxEXPAND);
1231 add_label_to_sizer (table, _panel, _("User name"), true);
1232 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1233 table->Add (_tms_user, 1, wxEXPAND);
1235 add_label_to_sizer (table, _panel, _("Password"), true);
1236 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1237 table->Add (_tms_password, 1, wxEXPAND);
1239 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1240 _tms_protocol->Append (_("FTP (for Dolby)"));
1242 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
1243 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
1244 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
1245 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
1246 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
1249 void config_changed ()
1251 Config* config = Config::instance ();
1253 checked_set (_tms_protocol, config->tms_protocol ());
1254 checked_set (_tms_ip, config->tms_ip ());
1255 checked_set (_tms_path, config->tms_path ());
1256 checked_set (_tms_user, config->tms_user ());
1257 checked_set (_tms_password, config->tms_password ());
1260 void tms_protocol_changed ()
1262 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1265 void tms_ip_changed ()
1267 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1270 void tms_path_changed ()
1272 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1275 void tms_user_changed ()
1277 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1280 void tms_password_changed ()
1282 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1285 wxChoice* _tms_protocol;
1286 wxTextCtrl* _tms_ip;
1287 wxTextCtrl* _tms_path;
1288 wxTextCtrl* _tms_user;
1289 wxTextCtrl* _tms_password;
1298 class KDMEmailPage : public StandardPage
1302 KDMEmailPage (wxSize panel_size, int border)
1303 #ifdef DCPOMATIC_OSX
1304 /* We have to force both width and height of this one */
1305 : StandardPage (wxSize (480, 128), border)
1307 : StandardPage (panel_size, border)
1311 wxString GetName () const
1313 return _("KDM Email");
1316 #ifdef DCPOMATIC_OSX
1317 wxBitmap GetLargeIcon () const
1319 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1326 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1327 table->AddGrowableCol (1, 1);
1328 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1330 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1332 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1333 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1334 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1335 add_label_to_sizer (s, _panel, _("port"), false);
1336 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1337 _mail_port->SetRange (0, 65535);
1338 s->Add (_mail_port);
1339 table->Add (s, 1, wxEXPAND | wxALL);
1342 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1343 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1344 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1346 add_label_to_sizer (table, _panel, _("Mail password"), true);
1347 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1348 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1350 add_label_to_sizer (table, _panel, _("Subject"), true);
1351 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1352 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1354 add_label_to_sizer (table, _panel, _("From address"), true);
1355 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1356 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1358 vector<string> columns;
1359 columns.push_back (wx_to_std (_("Address")));
1360 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1361 _kdm_cc = new EditableList<string, EmailDialog> (
1364 bind (&Config::kdm_cc, Config::instance()),
1365 bind (&Config::set_kdm_cc, Config::instance(), _1),
1368 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1370 add_label_to_sizer (table, _panel, _("BCC address"), true);
1371 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1372 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1374 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1375 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1377 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1378 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1382 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
1383 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
1384 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
1385 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
1386 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1387 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1388 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1389 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1390 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1393 void config_changed ()
1395 Config* config = Config::instance ();
1397 checked_set (_mail_server, config->mail_server ());
1398 checked_set (_mail_port, config->mail_port ());
1399 checked_set (_mail_user, config->mail_user ());
1400 checked_set (_mail_password, config->mail_password ());
1401 checked_set (_kdm_subject, config->kdm_subject ());
1402 checked_set (_kdm_from, config->kdm_from ());
1403 checked_set (_kdm_bcc, config->kdm_bcc ());
1404 checked_set (_kdm_email, Config::instance()->kdm_email ());
1407 void mail_server_changed ()
1409 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1412 void mail_port_changed ()
1414 Config::instance()->set_mail_port (_mail_port->GetValue ());
1417 void mail_user_changed ()
1419 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1422 void mail_password_changed ()
1424 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1427 void kdm_subject_changed ()
1429 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1432 void kdm_from_changed ()
1434 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1437 void kdm_bcc_changed ()
1439 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1442 void kdm_email_changed ()
1444 if (_kdm_email->GetValue().IsEmpty ()) {
1445 /* Sometimes we get sent an erroneous notification that the email
1446 is empty; I don't know why.
1450 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1453 void reset_kdm_email ()
1455 Config::instance()->reset_kdm_email ();
1456 checked_set (_kdm_email, Config::instance()->kdm_email ());
1459 wxTextCtrl* _mail_server;
1460 wxSpinCtrl* _mail_port;
1461 wxTextCtrl* _mail_user;
1462 wxTextCtrl* _mail_password;
1463 wxTextCtrl* _kdm_subject;
1464 wxTextCtrl* _kdm_from;
1465 EditableList<string, EmailDialog>* _kdm_cc;
1466 wxTextCtrl* _kdm_bcc;
1467 wxTextCtrl* _kdm_email;
1468 wxButton* _reset_kdm_email;
1471 /** @class AdvancedPage
1472 * @brief Advanced page of the preferences dialog.
1474 class AdvancedPage : public StockPage
1477 AdvancedPage (wxSize panel_size, int border)
1478 : StockPage (Kind_Advanced, panel_size, border)
1479 , _maximum_j2k_bandwidth (0)
1480 , _allow_any_dcp_frame_rate (0)
1481 , _only_servers_encode (0)
1486 , _log_debug_decode (0)
1487 , _log_debug_encode (0)
1488 , _log_debug_email (0)
1492 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1494 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1496 flags |= wxALIGN_RIGHT;
1499 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1500 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1505 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1506 table->AddGrowableCol (1, 1);
1507 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1510 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1511 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1512 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1513 s->Add (_maximum_j2k_bandwidth, 1);
1514 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1518 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1519 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1520 table->AddSpacer (0);
1522 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1523 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1524 table->AddSpacer (0);
1527 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1528 dcp::NameFormat::Map titles;
1529 titles['t'] = "type (cpl/pkl)";
1530 dcp::NameFormat::Map examples;
1531 examples['t'] = "cpl";
1532 _dcp_metadata_filename_format = new NameFormatEditor (
1533 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1535 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1539 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1540 dcp::NameFormat::Map titles;
1541 titles['t'] = "type (j2c/pcm/sub)";
1542 titles['r'] = "reel number";
1543 titles['n'] = "number of reels";
1544 titles['c'] = "content filename";
1545 dcp::NameFormat::Map examples;
1546 examples['t'] = "j2c";
1547 examples['r'] = "1";
1548 examples['n'] = "4";
1549 examples['c'] = "myfile.mp4";
1550 _dcp_asset_filename_format = new NameFormatEditor (
1551 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1553 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1557 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1558 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1559 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1560 t->Add (_log_general, 1, wxEXPAND | wxALL);
1561 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1562 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1563 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1564 t->Add (_log_error, 1, wxEXPAND | wxALL);
1565 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1566 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1567 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1568 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1569 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1570 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1571 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1572 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1573 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1574 table->Add (t, 0, wxALL, 6);
1577 #ifdef DCPOMATIC_WINDOWS
1578 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1579 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1580 table->AddSpacer (0);
1583 _maximum_j2k_bandwidth->SetRange (1, 1000);
1584 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1585 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1586 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1587 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1588 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1589 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1590 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1591 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1592 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1593 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1594 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1595 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1596 #ifdef DCPOMATIC_WINDOWS
1597 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1601 void config_changed ()
1603 Config* config = Config::instance ();
1605 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1606 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1607 checked_set (_only_servers_encode, config->only_servers_encode ());
1608 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1609 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1610 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1611 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1612 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1613 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1614 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1615 #ifdef DCPOMATIC_WINDOWS
1616 checked_set (_win32_console, config->win32_console());
1620 void maximum_j2k_bandwidth_changed ()
1622 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1625 void allow_any_dcp_frame_rate_changed ()
1627 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1630 void only_servers_encode_changed ()
1632 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1635 void dcp_metadata_filename_format_changed ()
1637 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1640 void dcp_asset_filename_format_changed ()
1642 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1648 if (_log_general->GetValue ()) {
1649 types |= LogEntry::TYPE_GENERAL;
1651 if (_log_warning->GetValue ()) {
1652 types |= LogEntry::TYPE_WARNING;
1654 if (_log_error->GetValue ()) {
1655 types |= LogEntry::TYPE_ERROR;
1657 if (_log_timing->GetValue ()) {
1658 types |= LogEntry::TYPE_TIMING;
1660 if (_log_debug_decode->GetValue ()) {
1661 types |= LogEntry::TYPE_DEBUG_DECODE;
1663 if (_log_debug_encode->GetValue ()) {
1664 types |= LogEntry::TYPE_DEBUG_ENCODE;
1666 if (_log_debug_email->GetValue ()) {
1667 types |= LogEntry::TYPE_DEBUG_EMAIL;
1669 Config::instance()->set_log_types (types);
1672 #ifdef DCPOMATIC_WINDOWS
1673 void win32_console_changed ()
1675 Config::instance()->set_win32_console (_win32_console->GetValue ());
1679 wxSpinCtrl* _maximum_j2k_bandwidth;
1680 wxCheckBox* _allow_any_dcp_frame_rate;
1681 wxCheckBox* _only_servers_encode;
1682 NameFormatEditor* _dcp_metadata_filename_format;
1683 NameFormatEditor* _dcp_asset_filename_format;
1684 wxCheckBox* _log_general;
1685 wxCheckBox* _log_warning;
1686 wxCheckBox* _log_error;
1687 wxCheckBox* _log_timing;
1688 wxCheckBox* _log_debug_decode;
1689 wxCheckBox* _log_debug_encode;
1690 wxCheckBox* _log_debug_email;
1691 #ifdef DCPOMATIC_WINDOWS
1692 wxCheckBox* _win32_console;
1696 wxPreferencesEditor*
1697 create_config_dialog ()
1699 wxPreferencesEditor* e = new wxPreferencesEditor ();
1701 #ifdef DCPOMATIC_OSX
1702 /* Width that we force some of the config panels to be on OSX so that
1703 the containing window doesn't shrink too much when we select those panels.
1704 This is obviously an unpleasant hack.
1706 wxSize ps = wxSize (520, -1);
1707 int const border = 16;
1709 wxSize ps = wxSize (-1, -1);
1710 int const border = 8;
1713 e->AddPage (new GeneralPage (ps, border));
1714 e->AddPage (new DefaultsPage (ps, border));
1715 e->AddPage (new EncodingServersPage (ps, border));
1716 e->AddPage (new KeysPage (ps, border));
1717 e->AddPage (new TMSPage (ps, border));
1718 e->AddPage (new KDMEmailPage (ps, border));
1719 e->AddPage (new AdvancedPage (ps, border));