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_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
239 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
240 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
242 _num_local_encoding_threads->SetRange (1, 128);
243 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
245 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
246 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
248 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
249 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
250 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
252 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
253 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, 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 _still_length->SetRange (1, 3600);
464 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
466 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
468 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
470 vector<Ratio const *> ratios = Ratio::all ();
471 for (size_t i = 0; i < ratios.size(); ++i) {
472 _container->Append (std_to_wx (ratios[i]->nickname ()));
475 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
477 vector<DCPContentType const *> const ct = DCPContentType::all ();
478 for (size_t i = 0; i < ct.size(); ++i) {
479 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
482 setup_audio_channels_choice (_dcp_audio_channels, 2);
484 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
485 _dcp_audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
487 _j2k_bandwidth->SetRange (50, 250);
488 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
490 _audio_delay->SetRange (-1000, 1000);
491 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
493 _standard->Append (_("SMPTE"));
494 _standard->Append (_("Interop"));
495 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
498 void config_changed ()
500 Config* config = Config::instance ();
502 vector<Ratio const *> ratios = Ratio::all ();
503 for (size_t i = 0; i < ratios.size(); ++i) {
504 if (ratios[i] == config->default_container ()) {
505 _container->SetSelection (i);
509 vector<DCPContentType const *> const ct = DCPContentType::all ();
510 for (size_t i = 0; i < ct.size(); ++i) {
511 if (ct[i] == config->default_dcp_content_type ()) {
512 _dcp_content_type->SetSelection (i);
516 checked_set (_still_length, config->default_still_length ());
517 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
518 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
519 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
520 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
521 checked_set (_audio_delay, config->default_audio_delay ());
522 checked_set (_standard, config->default_interop() ? 1 : 0);
525 void j2k_bandwidth_changed ()
527 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
530 void audio_delay_changed ()
532 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
535 void dcp_audio_channels_changed ()
537 int const s = _dcp_audio_channels->GetSelection ();
538 if (s != wxNOT_FOUND) {
539 Config::instance()->set_default_dcp_audio_channels (
540 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
545 void directory_changed ()
547 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
550 void edit_isdcf_metadata_clicked ()
552 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
554 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
558 void still_length_changed ()
560 Config::instance()->set_default_still_length (_still_length->GetValue ());
563 void container_changed ()
565 vector<Ratio const *> ratio = Ratio::all ();
566 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
569 void dcp_content_type_changed ()
571 vector<DCPContentType const *> ct = DCPContentType::all ();
572 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
575 void standard_changed ()
577 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
580 wxSpinCtrl* _j2k_bandwidth;
581 wxSpinCtrl* _audio_delay;
582 wxButton* _isdcf_metadata_button;
583 wxSpinCtrl* _still_length;
584 #ifdef DCPOMATIC_USE_OWN_PICKER
585 DirPickerCtrl* _directory;
587 wxDirPickerCtrl* _directory;
589 wxChoice* _container;
590 wxChoice* _dcp_content_type;
591 wxChoice* _dcp_audio_channels;
595 class EncodingServersPage : public StandardPage
598 EncodingServersPage (wxSize panel_size, int border)
599 : StandardPage (panel_size, border)
602 wxString GetName () const
608 wxBitmap GetLargeIcon () const
610 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
617 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
618 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
620 vector<string> columns;
621 columns.push_back (wx_to_std (_("IP address / host name")));
622 _servers_list = new EditableList<string, ServerDialog> (
625 boost::bind (&Config::servers, Config::instance()),
626 boost::bind (&Config::set_servers, Config::instance(), _1),
627 boost::bind (&EncodingServersPage::server_column, this, _1)
630 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
632 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
635 void config_changed ()
637 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
638 _servers_list->refresh ();
641 void use_any_servers_changed ()
643 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
646 string server_column (string s)
651 wxCheckBox* _use_any_servers;
652 EditableList<string, ServerDialog>* _servers_list;
655 class CertificateChainEditor : public wxPanel
658 CertificateChainEditor (
662 function<void (shared_ptr<dcp::CertificateChain>)> set,
663 function<shared_ptr<const dcp::CertificateChain> (void)> get
669 wxFont subheading_font (*wxNORMAL_FONT);
670 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
672 _sizer = new wxBoxSizer (wxVERTICAL);
675 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
676 m->SetFont (subheading_font);
677 _sizer->Add (m, 0, wxALL, border);
680 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
681 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
683 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
688 ip.SetText (_("Type"));
690 _certificates->InsertColumn (0, ip);
696 ip.SetText (_("Thumbprint"));
699 wxFont font = ip.GetFont ();
700 font.SetFamily (wxFONTFAMILY_TELETYPE);
703 _certificates->InsertColumn (1, ip);
706 certificates_sizer->Add (_certificates, 1, wxEXPAND);
709 wxSizer* s = new wxBoxSizer (wxVERTICAL);
710 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
711 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
712 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
713 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
714 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
715 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
716 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
719 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
720 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
723 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
724 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
725 wxFont font = _private_key->GetFont ();
726 font.SetFamily (wxFONTFAMILY_TELETYPE);
727 _private_key->SetFont (font);
728 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
729 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
730 table->Add (_load_private_key, wxGBPosition (r, 2));
731 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
732 table->Add (_export_private_key, wxGBPosition (r, 3));
735 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
736 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
737 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
738 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
741 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::add_certificate, this));
742 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remove_certificate, this));
743 _export_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_certificate, this));
744 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
745 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
746 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remake_certificates, this));
747 _load_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::load_private_key, this));
748 _export_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_private_key, this));
750 SetSizerAndFit (_sizer);
753 void config_changed ()
755 _chain.reset (new dcp::CertificateChain (*_get().get ()));
757 update_certificate_list ();
758 update_private_key ();
759 update_sensitivity ();
762 void add_button (wxWindow* button)
764 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
769 void add_certificate ()
771 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
773 if (d->ShowModal() == wxID_OK) {
776 string const extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
777 if (!extra.empty ()) {
780 _("This file contains other certificates (or other data) after its first certificate. "
781 "Only the first certificate will be used.")
786 update_certificate_list ();
787 } catch (dcp::MiscError& e) {
788 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
794 update_sensitivity ();
797 void remove_certificate ()
799 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
804 _certificates->DeleteItem (i);
808 update_sensitivity ();
811 void export_certificate ()
813 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
818 wxFileDialog* d = new wxFileDialog (
819 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
820 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
823 dcp::CertificateChain::List all = _chain->root_to_leaf ();
824 dcp::CertificateChain::List::iterator j = all.begin ();
825 for (int k = 0; k < i; ++k) {
829 if (d->ShowModal () == wxID_OK) {
830 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
832 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
835 string const s = j->certificate (true);
836 fwrite (s.c_str(), 1, s.length(), f);
842 void update_certificate_list ()
844 _certificates->DeleteAllItems ();
846 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
847 BOOST_FOREACH (dcp::Certificate const & i, certs) {
850 _certificates->InsertItem (item);
851 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
854 _certificates->SetItem (n, 0, _("Root"));
855 } else if (n == (certs.size() - 1)) {
856 _certificates->SetItem (n, 0, _("Leaf"));
858 _certificates->SetItem (n, 0, _("Intermediate"));
865 void remake_certificates ()
867 shared_ptr<const dcp::CertificateChain> chain = _get ();
869 string subject_organization_name;
870 string subject_organizational_unit_name;
871 string root_common_name;
872 string intermediate_common_name;
873 string leaf_common_name;
875 dcp::CertificateChain::List all = chain->root_to_leaf ();
877 if (all.size() >= 1) {
879 subject_organization_name = chain->root().subject_organization_name ();
880 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
881 root_common_name = chain->root().subject_common_name ();
884 if (all.size() >= 2) {
886 leaf_common_name = chain->leaf().subject_common_name ();
889 if (all.size() >= 3) {
890 /* Have an intermediate */
891 dcp::CertificateChain::List::iterator i = all.begin ();
893 intermediate_common_name = i->subject_common_name ();
896 MakeChainDialog* d = new MakeChainDialog (
898 subject_organization_name,
899 subject_organizational_unit_name,
901 intermediate_common_name,
905 if (d->ShowModal () == wxID_OK) {
907 new dcp::CertificateChain (
910 d->organisational_unit (),
911 d->root_common_name (),
912 d->intermediate_common_name (),
913 d->leaf_common_name ()
918 update_certificate_list ();
919 update_private_key ();
925 void update_sensitivity ()
927 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
928 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
931 void update_private_key ()
933 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
937 void load_private_key ()
939 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
941 if (d->ShowModal() == wxID_OK) {
943 boost::filesystem::path p (wx_to_std (d->GetPath ()));
944 if (boost::filesystem::file_size (p) > 8192) {
947 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
952 _chain->set_key (dcp::file_to_string (p));
954 update_private_key ();
955 } catch (dcp::MiscError& e) {
956 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
962 update_sensitivity ();
965 void export_private_key ()
967 optional<string> key = _chain->key ();
972 wxFileDialog* d = new wxFileDialog (
973 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
974 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
977 if (d->ShowModal () == wxID_OK) {
978 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
980 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
983 string const s = _chain->key().get ();
984 fwrite (s.c_str(), 1, s.length(), f);
990 wxListCtrl* _certificates;
991 wxButton* _add_certificate;
992 wxButton* _export_certificate;
993 wxButton* _remove_certificate;
994 wxButton* _remake_certificates;
995 wxStaticText* _private_key;
996 wxButton* _load_private_key;
997 wxButton* _export_private_key;
999 wxBoxSizer* _button_sizer;
1000 shared_ptr<dcp::CertificateChain> _chain;
1001 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1002 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1005 class KeysPage : public StandardPage
1008 KeysPage (wxSize panel_size, int border)
1009 : StandardPage (panel_size, border)
1012 wxString GetName () const
1017 #ifdef DCPOMATIC_OSX
1018 wxBitmap GetLargeIcon () const
1020 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1028 _signer = new CertificateChainEditor (
1029 _panel, _("Signing DCPs and KDMs"), _border,
1030 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1031 boost::bind (&Config::signer_chain, Config::instance ())
1034 _panel->GetSizer()->Add (_signer);
1036 _decryption = new CertificateChainEditor (
1037 _panel, _("Decrypting DCPs"), _border,
1038 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1039 boost::bind (&Config::decryption_chain, Config::instance ())
1042 _panel->GetSizer()->Add (_decryption);
1044 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1045 _decryption->add_button (_export_decryption_certificate);
1046 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1047 _decryption->add_button (_export_decryption_chain);
1049 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1050 _export_decryption_chain->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_chain, this));
1053 void export_decryption_certificate ()
1055 wxFileDialog* d = new wxFileDialog (
1056 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1057 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1060 if (d->ShowModal () == wxID_OK) {
1061 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1063 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1066 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1067 fwrite (s.c_str(), 1, s.length(), f);
1073 void export_decryption_chain ()
1075 wxFileDialog* d = new wxFileDialog (
1076 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1077 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1080 if (d->ShowModal () == wxID_OK) {
1081 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1083 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1086 string const s = Config::instance()->decryption_chain()->chain();
1087 fwrite (s.c_str(), 1, s.length(), f);
1093 void config_changed ()
1095 _signer->config_changed ();
1096 _decryption->config_changed ();
1099 CertificateChainEditor* _signer;
1100 CertificateChainEditor* _decryption;
1101 wxButton* _export_decryption_certificate;
1102 wxButton* _export_decryption_chain;
1105 class TMSPage : public StandardPage
1108 TMSPage (wxSize panel_size, int border)
1109 : StandardPage (panel_size, border)
1112 wxString GetName () const
1117 #ifdef DCPOMATIC_OSX
1118 wxBitmap GetLargeIcon () const
1120 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1127 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1128 table->AddGrowableCol (1, 1);
1129 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1131 add_label_to_sizer (table, _panel, _("Protocol"), true);
1132 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1133 table->Add (_tms_protocol, 1, wxEXPAND);
1135 add_label_to_sizer (table, _panel, _("IP address"), true);
1136 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1137 table->Add (_tms_ip, 1, wxEXPAND);
1139 add_label_to_sizer (table, _panel, _("Target path"), true);
1140 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1141 table->Add (_tms_path, 1, wxEXPAND);
1143 add_label_to_sizer (table, _panel, _("User name"), true);
1144 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1145 table->Add (_tms_user, 1, wxEXPAND);
1147 add_label_to_sizer (table, _panel, _("Password"), true);
1148 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1149 table->Add (_tms_password, 1, wxEXPAND);
1151 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1152 _tms_protocol->Append (_("FTP (for Dolby)"));
1154 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1155 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1156 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1157 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1158 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1161 void config_changed ()
1163 Config* config = Config::instance ();
1165 checked_set (_tms_protocol, config->tms_protocol ());
1166 checked_set (_tms_ip, config->tms_ip ());
1167 checked_set (_tms_path, config->tms_path ());
1168 checked_set (_tms_user, config->tms_user ());
1169 checked_set (_tms_password, config->tms_password ());
1172 void tms_protocol_changed ()
1174 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1177 void tms_ip_changed ()
1179 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1182 void tms_path_changed ()
1184 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1187 void tms_user_changed ()
1189 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1192 void tms_password_changed ()
1194 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1197 wxChoice* _tms_protocol;
1198 wxTextCtrl* _tms_ip;
1199 wxTextCtrl* _tms_path;
1200 wxTextCtrl* _tms_user;
1201 wxTextCtrl* _tms_password;
1210 class KDMEmailPage : public StandardPage
1214 KDMEmailPage (wxSize panel_size, int border)
1215 #ifdef DCPOMATIC_OSX
1216 /* We have to force both width and height of this one */
1217 : StandardPage (wxSize (480, 128), border)
1219 : StandardPage (panel_size, border)
1223 wxString GetName () const
1225 return _("KDM Email");
1228 #ifdef DCPOMATIC_OSX
1229 wxBitmap GetLargeIcon () const
1231 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1238 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1239 table->AddGrowableCol (1, 1);
1240 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1242 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1244 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1245 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1246 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1247 add_label_to_sizer (s, _panel, _("port"), false);
1248 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1249 _mail_port->SetRange (0, 65535);
1250 s->Add (_mail_port);
1251 table->Add (s, 1, wxEXPAND | wxALL);
1254 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1255 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1256 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1258 add_label_to_sizer (table, _panel, _("Mail password"), true);
1259 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1260 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1262 add_label_to_sizer (table, _panel, _("Subject"), true);
1263 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1264 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1266 add_label_to_sizer (table, _panel, _("From address"), true);
1267 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1268 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1270 vector<string> columns;
1271 columns.push_back (wx_to_std (_("Address")));
1272 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1273 _kdm_cc = new EditableList<string, EmailDialog> (
1276 bind (&Config::kdm_cc, Config::instance()),
1277 bind (&Config::set_kdm_cc, Config::instance(), _1),
1280 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1282 add_label_to_sizer (table, _panel, _("BCC address"), true);
1283 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1284 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1286 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1287 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1289 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1290 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1294 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1295 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1296 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1297 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1298 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1299 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1300 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1301 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1302 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1305 void config_changed ()
1307 Config* config = Config::instance ();
1309 checked_set (_mail_server, config->mail_server ());
1310 checked_set (_mail_port, config->mail_port ());
1311 checked_set (_mail_user, config->mail_user ());
1312 checked_set (_mail_password, config->mail_password ());
1313 checked_set (_kdm_subject, config->kdm_subject ());
1314 checked_set (_kdm_from, config->kdm_from ());
1315 checked_set (_kdm_bcc, config->kdm_bcc ());
1316 checked_set (_kdm_email, Config::instance()->kdm_email ());
1319 void mail_server_changed ()
1321 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1324 void mail_port_changed ()
1326 Config::instance()->set_mail_port (_mail_port->GetValue ());
1329 void mail_user_changed ()
1331 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1334 void mail_password_changed ()
1336 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1339 void kdm_subject_changed ()
1341 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1344 void kdm_from_changed ()
1346 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1349 void kdm_bcc_changed ()
1351 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1354 void kdm_email_changed ()
1356 if (_kdm_email->GetValue().IsEmpty ()) {
1357 /* Sometimes we get sent an erroneous notification that the email
1358 is empty; I don't know why.
1362 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1365 void reset_kdm_email ()
1367 Config::instance()->reset_kdm_email ();
1368 checked_set (_kdm_email, Config::instance()->kdm_email ());
1371 wxTextCtrl* _mail_server;
1372 wxSpinCtrl* _mail_port;
1373 wxTextCtrl* _mail_user;
1374 wxTextCtrl* _mail_password;
1375 wxTextCtrl* _kdm_subject;
1376 wxTextCtrl* _kdm_from;
1377 EditableList<string, EmailDialog>* _kdm_cc;
1378 wxTextCtrl* _kdm_bcc;
1379 wxTextCtrl* _kdm_email;
1380 wxButton* _reset_kdm_email;
1383 /** @class AdvancedPage
1384 * @brief Advanced page of the preferences dialog.
1386 class AdvancedPage : public StockPage
1389 AdvancedPage (wxSize panel_size, int border)
1390 : StockPage (Kind_Advanced, panel_size, border)
1391 , _maximum_j2k_bandwidth (0)
1392 , _allow_any_dcp_frame_rate (0)
1393 , _only_servers_encode (0)
1398 , _log_debug_decode (0)
1399 , _log_debug_encode (0)
1400 , _log_debug_email (0)
1404 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1406 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1408 flags |= wxALIGN_RIGHT;
1411 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1412 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1417 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1418 table->AddGrowableCol (1, 1);
1419 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1422 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1423 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1424 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1425 s->Add (_maximum_j2k_bandwidth, 1);
1426 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1430 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1431 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1432 table->AddSpacer (0);
1434 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1435 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1436 table->AddSpacer (0);
1439 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1440 dcp::NameFormat::Map titles;
1441 titles['t'] = "type (cpl/pkl)";
1442 dcp::NameFormat::Map examples;
1443 examples['t'] = "cpl";
1444 _dcp_metadata_filename_format = new NameFormatEditor (
1445 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1447 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1451 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1452 dcp::NameFormat::Map titles;
1453 titles['t'] = "type (j2c/pcm/sub)";
1454 titles['r'] = "reel number";
1455 titles['n'] = "number of reels";
1456 titles['c'] = "content filename";
1457 dcp::NameFormat::Map examples;
1458 examples['t'] = "j2c";
1459 examples['r'] = "1";
1460 examples['n'] = "4";
1461 examples['c'] = "myfile.mp4";
1462 _dcp_asset_filename_format = new NameFormatEditor (
1463 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1465 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1469 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1470 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1471 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1472 t->Add (_log_general, 1, wxEXPAND | wxALL);
1473 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1474 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1475 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1476 t->Add (_log_error, 1, wxEXPAND | wxALL);
1477 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1478 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1479 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1480 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1481 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1482 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1483 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1484 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1485 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1486 table->Add (t, 0, wxALL, 6);
1489 #ifdef DCPOMATIC_WINDOWS
1490 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1491 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1492 table->AddSpacer (0);
1495 _maximum_j2k_bandwidth->SetRange (1, 1000);
1496 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1497 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1498 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1499 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1500 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1501 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1502 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1503 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1504 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1505 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1506 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1507 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1508 #ifdef DCPOMATIC_WINDOWS
1509 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1513 void config_changed ()
1515 Config* config = Config::instance ();
1517 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1518 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1519 checked_set (_only_servers_encode, config->only_servers_encode ());
1520 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1521 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1522 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1523 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1524 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1525 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1526 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1527 #ifdef DCPOMATIC_WINDOWS
1528 checked_set (_win32_console, config->win32_console());
1532 void maximum_j2k_bandwidth_changed ()
1534 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1537 void allow_any_dcp_frame_rate_changed ()
1539 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1542 void only_servers_encode_changed ()
1544 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1547 void dcp_metadata_filename_format_changed ()
1549 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1552 void dcp_asset_filename_format_changed ()
1554 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1560 if (_log_general->GetValue ()) {
1561 types |= LogEntry::TYPE_GENERAL;
1563 if (_log_warning->GetValue ()) {
1564 types |= LogEntry::TYPE_WARNING;
1566 if (_log_error->GetValue ()) {
1567 types |= LogEntry::TYPE_ERROR;
1569 if (_log_timing->GetValue ()) {
1570 types |= LogEntry::TYPE_TIMING;
1572 if (_log_debug_decode->GetValue ()) {
1573 types |= LogEntry::TYPE_DEBUG_DECODE;
1575 if (_log_debug_encode->GetValue ()) {
1576 types |= LogEntry::TYPE_DEBUG_ENCODE;
1578 if (_log_debug_email->GetValue ()) {
1579 types |= LogEntry::TYPE_DEBUG_EMAIL;
1581 Config::instance()->set_log_types (types);
1584 #ifdef DCPOMATIC_WINDOWS
1585 void win32_console_changed ()
1587 Config::instance()->set_win32_console (_win32_console->GetValue ());
1591 wxSpinCtrl* _maximum_j2k_bandwidth;
1592 wxCheckBox* _allow_any_dcp_frame_rate;
1593 wxCheckBox* _only_servers_encode;
1594 NameFormatEditor* _dcp_metadata_filename_format;
1595 NameFormatEditor* _dcp_asset_filename_format;
1596 wxCheckBox* _log_general;
1597 wxCheckBox* _log_warning;
1598 wxCheckBox* _log_error;
1599 wxCheckBox* _log_timing;
1600 wxCheckBox* _log_debug_decode;
1601 wxCheckBox* _log_debug_encode;
1602 wxCheckBox* _log_debug_email;
1603 #ifdef DCPOMATIC_WINDOWS
1604 wxCheckBox* _win32_console;
1608 wxPreferencesEditor*
1609 create_config_dialog ()
1611 wxPreferencesEditor* e = new wxPreferencesEditor ();
1613 #ifdef DCPOMATIC_OSX
1614 /* Width that we force some of the config panels to be on OSX so that
1615 the containing window doesn't shrink too much when we select those panels.
1616 This is obviously an unpleasant hack.
1618 wxSize ps = wxSize (520, -1);
1619 int const border = 16;
1621 wxSize ps = wxSize (-1, -1);
1622 int const border = 8;
1625 e->AddPage (new GeneralPage (ps, border));
1626 e->AddPage (new DefaultsPage (ps, border));
1627 e->AddPage (new EncodingServersPage (ps, border));
1628 e->AddPage (new KeysPage (ps, border));
1629 e->AddPage (new TMSPage (ps, border));
1630 e->AddPage (new KDMEmailPage (ps, border));
1631 e->AddPage (new AdvancedPage (ps, border));