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>
51 #include <boost/filesystem.hpp>
52 #include <boost/foreach.hpp>
63 using boost::shared_ptr;
64 using boost::function;
65 using boost::optional;
66 using dcp::locale_convert;
71 Page (wxSize panel_size, int border)
74 , _panel_size (panel_size)
75 , _window_exists (false)
77 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
83 wxWindow* create_window (wxWindow* parent)
85 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
86 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
90 _window_exists = true;
93 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
102 virtual void config_changed () = 0;
103 virtual void setup () = 0;
105 void config_changed_wrapper ()
107 if (_window_exists) {
112 void window_destroyed ()
114 _window_exists = false;
118 boost::signals2::scoped_connection _config_connection;
122 class StockPage : public wxStockPreferencesPage, public Page
125 StockPage (Kind kind, wxSize panel_size, int border)
126 : wxStockPreferencesPage (kind)
127 , Page (panel_size, border)
130 wxWindow* CreateWindow (wxWindow* parent)
132 return create_window (parent);
136 class StandardPage : public wxPreferencesPage, public Page
139 StandardPage (wxSize panel_size, int border)
140 : Page (panel_size, border)
143 wxWindow* CreateWindow (wxWindow* parent)
145 return create_window (parent);
149 class GeneralPage : public StockPage
152 GeneralPage (wxSize panel_size, int border)
153 : StockPage (Kind_General, panel_size, border)
159 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
160 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
163 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
164 table->Add (_set_language, wxGBPosition (r, 0));
165 _language = new wxChoice (_panel, wxID_ANY);
166 vector<pair<string, string> > languages;
167 languages.push_back (make_pair ("Čeština", "cs_CZ"));
168 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
169 languages.push_back (make_pair ("Dansk", "da_DK"));
170 languages.push_back (make_pair ("Deutsch", "de_DE"));
171 languages.push_back (make_pair ("English", "en_GB"));
172 languages.push_back (make_pair ("Español", "es_ES"));
173 languages.push_back (make_pair ("Français", "fr_FR"));
174 languages.push_back (make_pair ("Italiano", "it_IT"));
175 languages.push_back (make_pair ("Nederlands", "nl_NL"));
176 languages.push_back (make_pair ("Русский", "ru_RU"));
177 languages.push_back (make_pair ("Polski", "pl_PL"));
178 languages.push_back (make_pair ("Português europeu", "pt_PT"));
179 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
180 languages.push_back (make_pair ("Svenska", "sv_SE"));
181 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
182 languages.push_back (make_pair ("українська мова", "uk_UA"));
183 checked_set (_language, languages);
184 table->Add (_language, wxGBPosition (r, 1));
187 wxStaticText* restart = add_label_to_sizer (
188 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
190 wxFont font = restart->GetFont();
191 font.SetStyle (wxFONTSTYLE_ITALIC);
192 font.SetPointSize (font.GetPointSize() - 1);
193 restart->SetFont (font);
196 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
197 _num_local_encoding_threads = new wxSpinCtrl (_panel);
198 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
201 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
202 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
203 table->Add (_cinemas_file, wxGBPosition (r, 1));
206 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
207 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
208 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
212 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
213 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
216 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
217 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
220 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
221 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
224 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
225 bottom_table->AddGrowableCol (1, 1);
227 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
228 _issuer = new wxTextCtrl (_panel, wxID_ANY);
229 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
231 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
232 _creator = new wxTextCtrl (_panel, wxID_ANY);
233 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
235 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
238 _set_language->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::set_language_changed, this));
239 _language->Bind (wxEVT_CHOICE, boost::bind (&GeneralPage::language_changed, this));
240 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
242 _num_local_encoding_threads->SetRange (1, 128);
243 _num_local_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
245 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
246 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
248 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
249 _check_for_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_updates_changed, this));
250 _check_for_test_updates->Bind (wxEVT_CHECKBOX, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
252 _issuer->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::issuer_changed, this));
253 _creator->Bind (wxEVT_TEXT, boost::bind (&GeneralPage::creator_changed, this));
256 void config_changed ()
258 Config* config = Config::instance ();
260 checked_set (_set_language, static_cast<bool>(config->language()));
262 /* Backwards compatibility of config file */
264 map<string, string> compat_map;
265 compat_map["fr"] = "fr_FR";
266 compat_map["it"] = "it_IT";
267 compat_map["es"] = "es_ES";
268 compat_map["sv"] = "sv_SE";
269 compat_map["de"] = "de_DE";
270 compat_map["nl"] = "nl_NL";
271 compat_map["ru"] = "ru_RU";
272 compat_map["pl"] = "pl_PL";
273 compat_map["da"] = "da_DK";
274 compat_map["pt"] = "pt_PT";
275 compat_map["sk"] = "sk_SK";
276 compat_map["cs"] = "cs_CZ";
277 compat_map["uk"] = "uk_UA";
279 string lang = config->language().get_value_or ("en_GB");
280 if (compat_map.find (lang) != compat_map.end ()) {
281 lang = compat_map[lang];
284 checked_set (_language, lang);
286 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
287 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
288 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
290 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
291 checked_set (_check_for_updates, config->check_for_updates ());
292 checked_set (_check_for_test_updates, config->check_for_test_updates ());
293 checked_set (_issuer, config->dcp_issuer ());
294 checked_set (_creator, config->dcp_creator ());
295 checked_set (_cinemas_file, config->cinemas_file());
297 setup_sensitivity ();
300 void setup_sensitivity ()
302 _language->Enable (_set_language->GetValue ());
303 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
306 void set_language_changed ()
308 setup_sensitivity ();
309 if (_set_language->GetValue ()) {
312 Config::instance()->unset_language ();
316 void language_changed ()
318 int const sel = _language->GetSelection ();
320 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
322 Config::instance()->unset_language ();
326 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
327 void analyse_ebur128_changed ()
329 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
333 void automatic_audio_analysis_changed ()
335 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
338 void check_for_updates_changed ()
340 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
343 void check_for_test_updates_changed ()
345 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
348 void num_local_encoding_threads_changed ()
350 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
353 void issuer_changed ()
355 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
358 void creator_changed ()
360 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
363 void cinemas_file_changed ()
365 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
368 wxCheckBox* _set_language;
370 wxSpinCtrl* _num_local_encoding_threads;
371 FilePickerCtrl* _cinemas_file;
372 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
373 wxCheckBox* _analyse_ebur128;
375 wxCheckBox* _automatic_audio_analysis;
376 wxCheckBox* _check_for_updates;
377 wxCheckBox* _check_for_test_updates;
379 wxTextCtrl* _creator;
382 class DefaultsPage : public StandardPage
385 DefaultsPage (wxSize panel_size, int border)
386 : StandardPage (panel_size, border)
389 wxString GetName () const
391 return _("Defaults");
395 wxBitmap GetLargeIcon () const
397 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
404 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
405 table->AddGrowableCol (1, 1);
406 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
409 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
410 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
411 _still_length = new wxSpinCtrl (_panel);
412 s->Add (_still_length);
413 add_label_to_sizer (s, _panel, _("s"), false);
417 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
418 #ifdef DCPOMATIC_USE_OWN_PICKER
419 _directory = new DirPickerCtrl (_panel);
421 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
423 table->Add (_directory, 1, wxEXPAND);
425 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
426 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
427 table->Add (_isdcf_metadata_button);
429 add_label_to_sizer (table, _panel, _("Default container"), true);
430 _container = new wxChoice (_panel, wxID_ANY);
431 table->Add (_container);
433 add_label_to_sizer (table, _panel, _("Default content type"), true);
434 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
435 table->Add (_dcp_content_type);
437 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
438 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
439 table->Add (_dcp_audio_channels);
442 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
443 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
444 _j2k_bandwidth = new wxSpinCtrl (_panel);
445 s->Add (_j2k_bandwidth);
446 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
451 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
452 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
453 _audio_delay = new wxSpinCtrl (_panel);
454 s->Add (_audio_delay);
455 add_label_to_sizer (s, _panel, _("ms"), false);
459 add_label_to_sizer (table, _panel, _("Default standard"), true);
460 _standard = new wxChoice (_panel, wxID_ANY);
461 table->Add (_standard);
463 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
464 #ifdef DCPOMATIC_USE_OWN_PICKER
465 _kdm_directory = new DirPickerCtrl (_panel);
467 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
469 table->Add (_kdm_directory, 1, wxEXPAND);
471 _still_length->SetRange (1, 3600);
472 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
474 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
475 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
477 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
479 vector<Ratio const *> ratios = Ratio::all ();
480 for (size_t i = 0; i < ratios.size(); ++i) {
481 _container->Append (std_to_wx (ratios[i]->nickname ()));
484 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
486 vector<DCPContentType const *> const ct = DCPContentType::all ();
487 for (size_t i = 0; i < ct.size(); ++i) {
488 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
491 setup_audio_channels_choice (_dcp_audio_channels, 2);
493 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
494 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
496 _j2k_bandwidth->SetRange (50, 250);
497 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
499 _audio_delay->SetRange (-1000, 1000);
500 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
502 _standard->Append (_("SMPTE"));
503 _standard->Append (_("Interop"));
504 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
507 void config_changed ()
509 Config* config = Config::instance ();
511 vector<Ratio const *> ratios = Ratio::all ();
512 for (size_t i = 0; i < ratios.size(); ++i) {
513 if (ratios[i] == config->default_container ()) {
514 _container->SetSelection (i);
518 vector<DCPContentType const *> const ct = DCPContentType::all ();
519 for (size_t i = 0; i < ct.size(); ++i) {
520 if (ct[i] == config->default_dcp_content_type ()) {
521 _dcp_content_type->SetSelection (i);
525 checked_set (_still_length, config->default_still_length ());
526 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
527 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
528 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
529 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
530 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
531 checked_set (_audio_delay, config->default_audio_delay ());
532 checked_set (_standard, config->default_interop() ? 1 : 0);
535 void j2k_bandwidth_changed ()
537 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
540 void audio_delay_changed ()
542 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
545 void dcp_audio_channels_changed ()
547 int const s = _dcp_audio_channels->GetSelection ();
548 if (s != wxNOT_FOUND) {
549 Config::instance()->set_default_dcp_audio_channels (
550 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
555 void directory_changed ()
557 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
560 void kdm_directory_changed ()
562 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
565 void edit_isdcf_metadata_clicked ()
567 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
569 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
573 void still_length_changed ()
575 Config::instance()->set_default_still_length (_still_length->GetValue ());
578 void container_changed ()
580 vector<Ratio const *> ratio = Ratio::all ();
581 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
584 void dcp_content_type_changed ()
586 vector<DCPContentType const *> ct = DCPContentType::all ();
587 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
590 void standard_changed ()
592 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
595 wxSpinCtrl* _j2k_bandwidth;
596 wxSpinCtrl* _audio_delay;
597 wxButton* _isdcf_metadata_button;
598 wxSpinCtrl* _still_length;
599 #ifdef DCPOMATIC_USE_OWN_PICKER
600 DirPickerCtrl* _directory;
601 DirPickerCtrl* _kdm_directory;
603 wxDirPickerCtrl* _directory;
604 wxDirPickerCtrl* _kdm_directory;
606 wxChoice* _container;
607 wxChoice* _dcp_content_type;
608 wxChoice* _dcp_audio_channels;
612 class EncodingServersPage : public StandardPage
615 EncodingServersPage (wxSize panel_size, int border)
616 : StandardPage (panel_size, border)
619 wxString GetName () const
625 wxBitmap GetLargeIcon () const
627 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
634 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
635 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
637 vector<string> columns;
638 columns.push_back (wx_to_std (_("IP address / host name")));
639 _servers_list = new EditableList<string, ServerDialog> (
642 boost::bind (&Config::servers, Config::instance()),
643 boost::bind (&Config::set_servers, Config::instance(), _1),
644 boost::bind (&EncodingServersPage::server_column, this, _1)
647 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
649 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
652 void config_changed ()
654 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
655 _servers_list->refresh ();
658 void use_any_servers_changed ()
660 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
663 string server_column (string s)
668 wxCheckBox* _use_any_servers;
669 EditableList<string, ServerDialog>* _servers_list;
672 class CertificateChainEditor : public wxPanel
675 CertificateChainEditor (
679 function<void (shared_ptr<dcp::CertificateChain>)> set,
680 function<shared_ptr<const dcp::CertificateChain> (void)> get
686 wxFont subheading_font (*wxNORMAL_FONT);
687 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
689 _sizer = new wxBoxSizer (wxVERTICAL);
692 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
693 m->SetFont (subheading_font);
694 _sizer->Add (m, 0, wxALL, border);
697 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
698 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
700 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
705 ip.SetText (_("Type"));
707 _certificates->InsertColumn (0, ip);
713 ip.SetText (_("Thumbprint"));
716 wxFont font = ip.GetFont ();
717 font.SetFamily (wxFONTFAMILY_TELETYPE);
720 _certificates->InsertColumn (1, ip);
723 certificates_sizer->Add (_certificates, 1, wxEXPAND);
726 wxSizer* s = new wxBoxSizer (wxVERTICAL);
727 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
728 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
729 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
730 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
731 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
732 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
733 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
736 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
737 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
740 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
741 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
742 wxFont font = _private_key->GetFont ();
743 font.SetFamily (wxFONTFAMILY_TELETYPE);
744 _private_key->SetFont (font);
745 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
746 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
747 table->Add (_load_private_key, wxGBPosition (r, 2));
748 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
749 table->Add (_export_private_key, wxGBPosition (r, 3));
752 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
753 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
754 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
755 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
758 _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this));
759 _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this));
760 _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this));
761 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
762 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
763 _remake_certificates->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remake_certificates, this));
764 _load_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::load_private_key, this));
765 _export_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_private_key, this));
767 SetSizerAndFit (_sizer);
770 void config_changed ()
772 _chain.reset (new dcp::CertificateChain (*_get().get ()));
774 update_certificate_list ();
775 update_private_key ();
776 update_sensitivity ();
779 void add_button (wxWindow* button)
781 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
786 void add_certificate ()
788 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
790 if (d->ShowModal() == wxID_OK) {
793 string const extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
794 if (!extra.empty ()) {
797 _("This file contains other certificates (or other data) after its first certificate. "
798 "Only the first certificate will be used.")
803 update_certificate_list ();
804 } catch (dcp::MiscError& e) {
805 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
811 update_sensitivity ();
814 void remove_certificate ()
816 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
821 _certificates->DeleteItem (i);
825 update_sensitivity ();
828 void export_certificate ()
830 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
835 wxFileDialog* d = new wxFileDialog (
836 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
837 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
840 dcp::CertificateChain::List all = _chain->root_to_leaf ();
841 dcp::CertificateChain::List::iterator j = all.begin ();
842 for (int k = 0; k < i; ++k) {
846 if (d->ShowModal () == wxID_OK) {
847 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
849 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
852 string const s = j->certificate (true);
853 fwrite (s.c_str(), 1, s.length(), f);
859 void update_certificate_list ()
861 _certificates->DeleteAllItems ();
863 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
864 BOOST_FOREACH (dcp::Certificate const & i, certs) {
867 _certificates->InsertItem (item);
868 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
871 _certificates->SetItem (n, 0, _("Root"));
872 } else if (n == (certs.size() - 1)) {
873 _certificates->SetItem (n, 0, _("Leaf"));
875 _certificates->SetItem (n, 0, _("Intermediate"));
882 void remake_certificates ()
884 shared_ptr<const dcp::CertificateChain> chain = _get ();
886 string subject_organization_name;
887 string subject_organizational_unit_name;
888 string root_common_name;
889 string intermediate_common_name;
890 string leaf_common_name;
892 dcp::CertificateChain::List all = chain->root_to_leaf ();
894 if (all.size() >= 1) {
896 subject_organization_name = chain->root().subject_organization_name ();
897 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
898 root_common_name = chain->root().subject_common_name ();
901 if (all.size() >= 2) {
903 leaf_common_name = chain->leaf().subject_common_name ();
906 if (all.size() >= 3) {
907 /* Have an intermediate */
908 dcp::CertificateChain::List::iterator i = all.begin ();
910 intermediate_common_name = i->subject_common_name ();
913 MakeChainDialog* d = new MakeChainDialog (
915 subject_organization_name,
916 subject_organizational_unit_name,
918 intermediate_common_name,
922 if (d->ShowModal () == wxID_OK) {
924 new dcp::CertificateChain (
927 d->organisational_unit (),
928 d->root_common_name (),
929 d->intermediate_common_name (),
930 d->leaf_common_name ()
935 update_certificate_list ();
936 update_private_key ();
942 void update_sensitivity ()
944 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
945 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
948 void update_private_key ()
950 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
954 void load_private_key ()
956 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
958 if (d->ShowModal() == wxID_OK) {
960 boost::filesystem::path p (wx_to_std (d->GetPath ()));
961 if (boost::filesystem::file_size (p) > 8192) {
964 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
969 _chain->set_key (dcp::file_to_string (p));
971 update_private_key ();
972 } catch (dcp::MiscError& e) {
973 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
979 update_sensitivity ();
982 void export_private_key ()
984 optional<string> key = _chain->key ();
989 wxFileDialog* d = new wxFileDialog (
990 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
991 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
994 if (d->ShowModal () == wxID_OK) {
995 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
997 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1000 string const s = _chain->key().get ();
1001 fwrite (s.c_str(), 1, s.length(), f);
1007 wxListCtrl* _certificates;
1008 wxButton* _add_certificate;
1009 wxButton* _export_certificate;
1010 wxButton* _remove_certificate;
1011 wxButton* _remake_certificates;
1012 wxStaticText* _private_key;
1013 wxButton* _load_private_key;
1014 wxButton* _export_private_key;
1016 wxBoxSizer* _button_sizer;
1017 shared_ptr<dcp::CertificateChain> _chain;
1018 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1019 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1022 class KeysPage : public StandardPage
1025 KeysPage (wxSize panel_size, int border)
1026 : StandardPage (panel_size, border)
1029 wxString GetName () const
1034 #ifdef DCPOMATIC_OSX
1035 wxBitmap GetLargeIcon () const
1037 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1045 _signer = new CertificateChainEditor (
1046 _panel, _("Signing DCPs and KDMs"), _border,
1047 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1048 boost::bind (&Config::signer_chain, Config::instance ())
1051 _panel->GetSizer()->Add (_signer);
1053 _decryption = new CertificateChainEditor (
1054 _panel, _("Decrypting DCPs"), _border,
1055 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1056 boost::bind (&Config::decryption_chain, Config::instance ())
1059 _panel->GetSizer()->Add (_decryption);
1061 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1062 _decryption->add_button (_export_decryption_certificate);
1063 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1064 _decryption->add_button (_export_decryption_chain);
1066 _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
1067 _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
1070 void export_decryption_certificate ()
1072 wxFileDialog* d = new wxFileDialog (
1073 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1074 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1077 if (d->ShowModal () == wxID_OK) {
1078 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1080 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1083 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1084 fwrite (s.c_str(), 1, s.length(), f);
1090 void export_decryption_chain ()
1092 wxFileDialog* d = new wxFileDialog (
1093 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1094 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1097 if (d->ShowModal () == wxID_OK) {
1098 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1100 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1103 string const s = Config::instance()->decryption_chain()->chain();
1104 fwrite (s.c_str(), 1, s.length(), f);
1110 void config_changed ()
1112 _signer->config_changed ();
1113 _decryption->config_changed ();
1116 CertificateChainEditor* _signer;
1117 CertificateChainEditor* _decryption;
1118 wxButton* _export_decryption_certificate;
1119 wxButton* _export_decryption_chain;
1122 class TMSPage : public StandardPage
1125 TMSPage (wxSize panel_size, int border)
1126 : StandardPage (panel_size, border)
1129 wxString GetName () const
1134 #ifdef DCPOMATIC_OSX
1135 wxBitmap GetLargeIcon () const
1137 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1144 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1145 table->AddGrowableCol (1, 1);
1146 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1148 add_label_to_sizer (table, _panel, _("Protocol"), true);
1149 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1150 table->Add (_tms_protocol, 1, wxEXPAND);
1152 add_label_to_sizer (table, _panel, _("IP address"), true);
1153 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1154 table->Add (_tms_ip, 1, wxEXPAND);
1156 add_label_to_sizer (table, _panel, _("Target path"), true);
1157 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1158 table->Add (_tms_path, 1, wxEXPAND);
1160 add_label_to_sizer (table, _panel, _("User name"), true);
1161 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1162 table->Add (_tms_user, 1, wxEXPAND);
1164 add_label_to_sizer (table, _panel, _("Password"), true);
1165 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1166 table->Add (_tms_password, 1, wxEXPAND);
1168 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1169 _tms_protocol->Append (_("FTP (for Dolby)"));
1171 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
1172 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
1173 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
1174 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
1175 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
1178 void config_changed ()
1180 Config* config = Config::instance ();
1182 checked_set (_tms_protocol, config->tms_protocol ());
1183 checked_set (_tms_ip, config->tms_ip ());
1184 checked_set (_tms_path, config->tms_path ());
1185 checked_set (_tms_user, config->tms_user ());
1186 checked_set (_tms_password, config->tms_password ());
1189 void tms_protocol_changed ()
1191 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1194 void tms_ip_changed ()
1196 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1199 void tms_path_changed ()
1201 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1204 void tms_user_changed ()
1206 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1209 void tms_password_changed ()
1211 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1214 wxChoice* _tms_protocol;
1215 wxTextCtrl* _tms_ip;
1216 wxTextCtrl* _tms_path;
1217 wxTextCtrl* _tms_user;
1218 wxTextCtrl* _tms_password;
1227 class KDMEmailPage : public StandardPage
1231 KDMEmailPage (wxSize panel_size, int border)
1232 #ifdef DCPOMATIC_OSX
1233 /* We have to force both width and height of this one */
1234 : StandardPage (wxSize (480, 128), border)
1236 : StandardPage (panel_size, border)
1240 wxString GetName () const
1242 return _("KDM Email");
1245 #ifdef DCPOMATIC_OSX
1246 wxBitmap GetLargeIcon () const
1248 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1255 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1256 table->AddGrowableCol (1, 1);
1257 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1259 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1261 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1262 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1263 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1264 add_label_to_sizer (s, _panel, _("port"), false);
1265 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1266 _mail_port->SetRange (0, 65535);
1267 s->Add (_mail_port);
1268 table->Add (s, 1, wxEXPAND | wxALL);
1271 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1272 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1273 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1275 add_label_to_sizer (table, _panel, _("Mail password"), true);
1276 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1277 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1279 add_label_to_sizer (table, _panel, _("Subject"), true);
1280 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1281 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1283 add_label_to_sizer (table, _panel, _("From address"), true);
1284 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1285 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1287 vector<string> columns;
1288 columns.push_back (wx_to_std (_("Address")));
1289 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1290 _kdm_cc = new EditableList<string, EmailDialog> (
1293 bind (&Config::kdm_cc, Config::instance()),
1294 bind (&Config::set_kdm_cc, Config::instance(), _1),
1297 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1299 add_label_to_sizer (table, _panel, _("BCC address"), true);
1300 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1301 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1303 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1304 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1306 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1307 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1311 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
1312 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
1313 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
1314 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
1315 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1316 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1317 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1318 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1319 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1322 void config_changed ()
1324 Config* config = Config::instance ();
1326 checked_set (_mail_server, config->mail_server ());
1327 checked_set (_mail_port, config->mail_port ());
1328 checked_set (_mail_user, config->mail_user ());
1329 checked_set (_mail_password, config->mail_password ());
1330 checked_set (_kdm_subject, config->kdm_subject ());
1331 checked_set (_kdm_from, config->kdm_from ());
1332 checked_set (_kdm_bcc, config->kdm_bcc ());
1333 checked_set (_kdm_email, Config::instance()->kdm_email ());
1336 void mail_server_changed ()
1338 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1341 void mail_port_changed ()
1343 Config::instance()->set_mail_port (_mail_port->GetValue ());
1346 void mail_user_changed ()
1348 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1351 void mail_password_changed ()
1353 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1356 void kdm_subject_changed ()
1358 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1361 void kdm_from_changed ()
1363 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1366 void kdm_bcc_changed ()
1368 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1371 void kdm_email_changed ()
1373 if (_kdm_email->GetValue().IsEmpty ()) {
1374 /* Sometimes we get sent an erroneous notification that the email
1375 is empty; I don't know why.
1379 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1382 void reset_kdm_email ()
1384 Config::instance()->reset_kdm_email ();
1385 checked_set (_kdm_email, Config::instance()->kdm_email ());
1388 wxTextCtrl* _mail_server;
1389 wxSpinCtrl* _mail_port;
1390 wxTextCtrl* _mail_user;
1391 wxTextCtrl* _mail_password;
1392 wxTextCtrl* _kdm_subject;
1393 wxTextCtrl* _kdm_from;
1394 EditableList<string, EmailDialog>* _kdm_cc;
1395 wxTextCtrl* _kdm_bcc;
1396 wxTextCtrl* _kdm_email;
1397 wxButton* _reset_kdm_email;
1400 /** @class AdvancedPage
1401 * @brief Advanced page of the preferences dialog.
1403 class AdvancedPage : public StockPage
1406 AdvancedPage (wxSize panel_size, int border)
1407 : StockPage (Kind_Advanced, panel_size, border)
1408 , _maximum_j2k_bandwidth (0)
1409 , _allow_any_dcp_frame_rate (0)
1410 , _only_servers_encode (0)
1415 , _log_debug_decode (0)
1416 , _log_debug_encode (0)
1417 , _log_debug_email (0)
1421 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1423 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1425 flags |= wxALIGN_RIGHT;
1428 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1429 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1434 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1435 table->AddGrowableCol (1, 1);
1436 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1439 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1440 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1441 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1442 s->Add (_maximum_j2k_bandwidth, 1);
1443 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1447 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1448 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1449 table->AddSpacer (0);
1451 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1452 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1453 table->AddSpacer (0);
1456 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1457 dcp::NameFormat::Map titles;
1458 titles['t'] = "type (cpl/pkl)";
1459 dcp::NameFormat::Map examples;
1460 examples['t'] = "cpl";
1461 _dcp_metadata_filename_format = new NameFormatEditor (
1462 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1464 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1468 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1469 dcp::NameFormat::Map titles;
1470 titles['t'] = "type (j2c/pcm/sub)";
1471 titles['r'] = "reel number";
1472 titles['n'] = "number of reels";
1473 titles['c'] = "content filename";
1474 dcp::NameFormat::Map examples;
1475 examples['t'] = "j2c";
1476 examples['r'] = "1";
1477 examples['n'] = "4";
1478 examples['c'] = "myfile.mp4";
1479 _dcp_asset_filename_format = new NameFormatEditor (
1480 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1482 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1486 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1487 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1488 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1489 t->Add (_log_general, 1, wxEXPAND | wxALL);
1490 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1491 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1492 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1493 t->Add (_log_error, 1, wxEXPAND | wxALL);
1494 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1495 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1496 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1497 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1498 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1499 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1500 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1501 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1502 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1503 table->Add (t, 0, wxALL, 6);
1506 #ifdef DCPOMATIC_WINDOWS
1507 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1508 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1509 table->AddSpacer (0);
1512 _maximum_j2k_bandwidth->SetRange (1, 1000);
1513 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1514 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1515 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1516 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1517 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1518 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1519 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1520 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1521 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1522 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1523 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1524 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1525 #ifdef DCPOMATIC_WINDOWS
1526 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1530 void config_changed ()
1532 Config* config = Config::instance ();
1534 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1535 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1536 checked_set (_only_servers_encode, config->only_servers_encode ());
1537 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1538 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1539 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1540 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1541 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1542 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1543 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1544 #ifdef DCPOMATIC_WINDOWS
1545 checked_set (_win32_console, config->win32_console());
1549 void maximum_j2k_bandwidth_changed ()
1551 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1554 void allow_any_dcp_frame_rate_changed ()
1556 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1559 void only_servers_encode_changed ()
1561 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1564 void dcp_metadata_filename_format_changed ()
1566 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1569 void dcp_asset_filename_format_changed ()
1571 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1577 if (_log_general->GetValue ()) {
1578 types |= LogEntry::TYPE_GENERAL;
1580 if (_log_warning->GetValue ()) {
1581 types |= LogEntry::TYPE_WARNING;
1583 if (_log_error->GetValue ()) {
1584 types |= LogEntry::TYPE_ERROR;
1586 if (_log_timing->GetValue ()) {
1587 types |= LogEntry::TYPE_TIMING;
1589 if (_log_debug_decode->GetValue ()) {
1590 types |= LogEntry::TYPE_DEBUG_DECODE;
1592 if (_log_debug_encode->GetValue ()) {
1593 types |= LogEntry::TYPE_DEBUG_ENCODE;
1595 if (_log_debug_email->GetValue ()) {
1596 types |= LogEntry::TYPE_DEBUG_EMAIL;
1598 Config::instance()->set_log_types (types);
1601 #ifdef DCPOMATIC_WINDOWS
1602 void win32_console_changed ()
1604 Config::instance()->set_win32_console (_win32_console->GetValue ());
1608 wxSpinCtrl* _maximum_j2k_bandwidth;
1609 wxCheckBox* _allow_any_dcp_frame_rate;
1610 wxCheckBox* _only_servers_encode;
1611 NameFormatEditor* _dcp_metadata_filename_format;
1612 NameFormatEditor* _dcp_asset_filename_format;
1613 wxCheckBox* _log_general;
1614 wxCheckBox* _log_warning;
1615 wxCheckBox* _log_error;
1616 wxCheckBox* _log_timing;
1617 wxCheckBox* _log_debug_decode;
1618 wxCheckBox* _log_debug_encode;
1619 wxCheckBox* _log_debug_email;
1620 #ifdef DCPOMATIC_WINDOWS
1621 wxCheckBox* _win32_console;
1625 wxPreferencesEditor*
1626 create_config_dialog ()
1628 wxPreferencesEditor* e = new wxPreferencesEditor ();
1630 #ifdef DCPOMATIC_OSX
1631 /* Width that we force some of the config panels to be on OSX so that
1632 the containing window doesn't shrink too much when we select those panels.
1633 This is obviously an unpleasant hack.
1635 wxSize ps = wxSize (520, -1);
1636 int const border = 16;
1638 wxSize ps = wxSize (-1, -1);
1639 int const border = 8;
1642 e->AddPage (new GeneralPage (ps, border));
1643 e->AddPage (new DefaultsPage (ps, border));
1644 e->AddPage (new EncodingServersPage (ps, border));
1645 e->AddPage (new KeysPage (ps, border));
1646 e->AddPage (new TMSPage (ps, border));
1647 e->AddPage (new KDMEmailPage (ps, border));
1648 e->AddPage (new AdvancedPage (ps, border));