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 "lib/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;
70 Page (wxSize panel_size, int border)
73 , _panel_size (panel_size)
74 , _window_exists (false)
76 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
82 wxWindow* create_window (wxWindow* parent)
84 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
85 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
89 _window_exists = true;
92 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
101 virtual void config_changed () = 0;
102 virtual void setup () = 0;
104 void config_changed_wrapper ()
106 if (_window_exists) {
111 void window_destroyed ()
113 _window_exists = false;
117 boost::signals2::scoped_connection _config_connection;
121 class StockPage : public wxStockPreferencesPage, public Page
124 StockPage (Kind kind, wxSize panel_size, int border)
125 : wxStockPreferencesPage (kind)
126 , Page (panel_size, border)
129 wxWindow* CreateWindow (wxWindow* parent)
131 return create_window (parent);
135 class StandardPage : public wxPreferencesPage, public Page
138 StandardPage (wxSize panel_size, int border)
139 : Page (panel_size, border)
142 wxWindow* CreateWindow (wxWindow* parent)
144 return create_window (parent);
148 class GeneralPage : public StockPage
151 GeneralPage (wxSize panel_size, int border)
152 : StockPage (Kind_General, panel_size, border)
158 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
159 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
162 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
163 table->Add (_set_language, wxGBPosition (r, 0));
164 _language = new wxChoice (_panel, wxID_ANY);
165 vector<pair<string, string> > languages;
166 languages.push_back (make_pair ("Čeština", "cs_CZ"));
167 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
168 languages.push_back (make_pair ("Dansk", "da_DK"));
169 languages.push_back (make_pair ("Deutsch", "de_DE"));
170 languages.push_back (make_pair ("English", "en_GB"));
171 languages.push_back (make_pair ("Español", "es_ES"));
172 languages.push_back (make_pair ("Français", "fr_FR"));
173 languages.push_back (make_pair ("Italiano", "it_IT"));
174 languages.push_back (make_pair ("Nederlands", "nl_NL"));
175 languages.push_back (make_pair ("Русский", "ru_RU"));
176 languages.push_back (make_pair ("Polski", "pl_PL"));
177 languages.push_back (make_pair ("Português europeu", "pt_PT"));
178 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
179 languages.push_back (make_pair ("Svenska", "sv_SE"));
180 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
181 languages.push_back (make_pair ("українська мова", "uk_UA"));
182 checked_set (_language, languages);
183 table->Add (_language, wxGBPosition (r, 1));
186 wxStaticText* restart = add_label_to_sizer (
187 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
189 wxFont font = restart->GetFont();
190 font.SetStyle (wxFONTSTYLE_ITALIC);
191 font.SetPointSize (font.GetPointSize() - 1);
192 restart->SetFont (font);
195 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
196 _num_local_encoding_threads = new wxSpinCtrl (_panel);
197 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
200 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
201 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
202 table->Add (_cinemas_file, wxGBPosition (r, 1));
205 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
206 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
207 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
211 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
212 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
215 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
216 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
219 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
220 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
223 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
224 bottom_table->AddGrowableCol (1, 1);
226 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
227 _issuer = new wxTextCtrl (_panel, wxID_ANY);
228 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
230 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
231 _creator = new wxTextCtrl (_panel, wxID_ANY);
232 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
234 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
237 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
238 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
239 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
241 _num_local_encoding_threads->SetRange (1, 128);
242 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
244 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
245 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
247 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
248 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
249 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
251 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
252 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::creator_changed, this));
255 void config_changed ()
257 Config* config = Config::instance ();
259 checked_set (_set_language, static_cast<bool>(config->language()));
261 /* Backwards compatibility of config file */
263 map<string, string> compat_map;
264 compat_map["fr"] = "fr_FR";
265 compat_map["it"] = "it_IT";
266 compat_map["es"] = "es_ES";
267 compat_map["sv"] = "sv_SE";
268 compat_map["de"] = "de_DE";
269 compat_map["nl"] = "nl_NL";
270 compat_map["ru"] = "ru_RU";
271 compat_map["pl"] = "pl_PL";
272 compat_map["da"] = "da_DK";
273 compat_map["pt"] = "pt_PT";
274 compat_map["sk"] = "sk_SK";
275 compat_map["cs"] = "cs_CZ";
276 compat_map["uk"] = "uk_UA";
278 string lang = config->language().get_value_or ("en_GB");
279 if (compat_map.find (lang) != compat_map.end ()) {
280 lang = compat_map[lang];
283 checked_set (_language, lang);
285 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
286 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
287 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
289 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
290 checked_set (_check_for_updates, config->check_for_updates ());
291 checked_set (_check_for_test_updates, config->check_for_test_updates ());
292 checked_set (_issuer, config->dcp_issuer ());
293 checked_set (_creator, config->dcp_creator ());
294 checked_set (_cinemas_file, config->cinemas_file());
296 setup_sensitivity ();
299 void setup_sensitivity ()
301 _language->Enable (_set_language->GetValue ());
302 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
305 void set_language_changed ()
307 setup_sensitivity ();
308 if (_set_language->GetValue ()) {
311 Config::instance()->unset_language ();
315 void language_changed ()
317 int const sel = _language->GetSelection ();
319 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
321 Config::instance()->unset_language ();
325 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
326 void analyse_ebur128_changed ()
328 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
332 void automatic_audio_analysis_changed ()
334 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
337 void check_for_updates_changed ()
339 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
342 void check_for_test_updates_changed ()
344 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
347 void num_local_encoding_threads_changed ()
349 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
352 void issuer_changed ()
354 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
357 void creator_changed ()
359 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
362 void cinemas_file_changed ()
364 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
367 wxCheckBox* _set_language;
369 wxSpinCtrl* _num_local_encoding_threads;
370 FilePickerCtrl* _cinemas_file;
371 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
372 wxCheckBox* _analyse_ebur128;
374 wxCheckBox* _automatic_audio_analysis;
375 wxCheckBox* _check_for_updates;
376 wxCheckBox* _check_for_test_updates;
378 wxTextCtrl* _creator;
381 class DefaultsPage : public StandardPage
384 DefaultsPage (wxSize panel_size, int border)
385 : StandardPage (panel_size, border)
388 wxString GetName () const
390 return _("Defaults");
394 wxBitmap GetLargeIcon () const
396 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
403 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
404 table->AddGrowableCol (1, 1);
405 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
408 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
409 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
410 _still_length = new wxSpinCtrl (_panel);
411 s->Add (_still_length);
412 add_label_to_sizer (s, _panel, _("s"), false);
416 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
417 #ifdef DCPOMATIC_USE_OWN_PICKER
418 _directory = new DirPickerCtrl (_panel);
420 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
422 table->Add (_directory, 1, wxEXPAND);
424 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
425 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
426 table->Add (_isdcf_metadata_button);
428 add_label_to_sizer (table, _panel, _("Default container"), true);
429 _container = new wxChoice (_panel, wxID_ANY);
430 table->Add (_container);
432 add_label_to_sizer (table, _panel, _("Default content type"), true);
433 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
434 table->Add (_dcp_content_type);
436 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
437 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
438 table->Add (_dcp_audio_channels);
441 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
442 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
443 _j2k_bandwidth = new wxSpinCtrl (_panel);
444 s->Add (_j2k_bandwidth);
445 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
450 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
451 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
452 _audio_delay = new wxSpinCtrl (_panel);
453 s->Add (_audio_delay);
454 add_label_to_sizer (s, _panel, _("ms"), false);
458 add_label_to_sizer (table, _panel, _("Default standard"), true);
459 _standard = new wxChoice (_panel, wxID_ANY);
460 table->Add (_standard);
462 _still_length->SetRange (1, 3600);
463 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
465 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
467 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
469 vector<Ratio const *> ratios = Ratio::all ();
470 for (size_t i = 0; i < ratios.size(); ++i) {
471 _container->Append (std_to_wx (ratios[i]->nickname ()));
474 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
476 vector<DCPContentType const *> const ct = DCPContentType::all ();
477 for (size_t i = 0; i < ct.size(); ++i) {
478 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
481 setup_audio_channels_choice (_dcp_audio_channels, 2);
483 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
484 _dcp_audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
486 _j2k_bandwidth->SetRange (50, 250);
487 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
489 _audio_delay->SetRange (-1000, 1000);
490 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
492 _standard->Append (_("SMPTE"));
493 _standard->Append (_("Interop"));
494 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
497 void config_changed ()
499 Config* config = Config::instance ();
501 vector<Ratio const *> ratios = Ratio::all ();
502 for (size_t i = 0; i < ratios.size(); ++i) {
503 if (ratios[i] == config->default_container ()) {
504 _container->SetSelection (i);
508 vector<DCPContentType const *> const ct = DCPContentType::all ();
509 for (size_t i = 0; i < ct.size(); ++i) {
510 if (ct[i] == config->default_dcp_content_type ()) {
511 _dcp_content_type->SetSelection (i);
515 checked_set (_still_length, config->default_still_length ());
516 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
517 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
518 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
519 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
520 checked_set (_audio_delay, config->default_audio_delay ());
521 checked_set (_standard, config->default_interop() ? 1 : 0);
524 void j2k_bandwidth_changed ()
526 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
529 void audio_delay_changed ()
531 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
534 void dcp_audio_channels_changed ()
536 int const s = _dcp_audio_channels->GetSelection ();
537 if (s != wxNOT_FOUND) {
538 Config::instance()->set_default_dcp_audio_channels (
539 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
544 void directory_changed ()
546 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
549 void edit_isdcf_metadata_clicked ()
551 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
553 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
557 void still_length_changed ()
559 Config::instance()->set_default_still_length (_still_length->GetValue ());
562 void container_changed ()
564 vector<Ratio const *> ratio = Ratio::all ();
565 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
568 void dcp_content_type_changed ()
570 vector<DCPContentType const *> ct = DCPContentType::all ();
571 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
574 void standard_changed ()
576 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
579 wxSpinCtrl* _j2k_bandwidth;
580 wxSpinCtrl* _audio_delay;
581 wxButton* _isdcf_metadata_button;
582 wxSpinCtrl* _still_length;
583 #ifdef DCPOMATIC_USE_OWN_PICKER
584 DirPickerCtrl* _directory;
586 wxDirPickerCtrl* _directory;
588 wxChoice* _container;
589 wxChoice* _dcp_content_type;
590 wxChoice* _dcp_audio_channels;
594 class EncodingServersPage : public StandardPage
597 EncodingServersPage (wxSize panel_size, int border)
598 : StandardPage (panel_size, border)
601 wxString GetName () const
607 wxBitmap GetLargeIcon () const
609 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
616 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
617 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
619 vector<string> columns;
620 columns.push_back (wx_to_std (_("IP address / host name")));
621 _servers_list = new EditableList<string, ServerDialog> (
624 boost::bind (&Config::servers, Config::instance()),
625 boost::bind (&Config::set_servers, Config::instance(), _1),
626 boost::bind (&always_valid),
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) {
775 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
776 if (c.extra_data ()) {
779 _("This file contains other certificates (or other data) after its first certificate. "
780 "Only the first certificate will be used.")
785 update_certificate_list ();
786 } catch (dcp::MiscError& e) {
787 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
793 update_sensitivity ();
796 void remove_certificate ()
798 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
803 _certificates->DeleteItem (i);
807 update_sensitivity ();
810 void export_certificate ()
812 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
817 wxFileDialog* d = new wxFileDialog (
818 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
819 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
822 dcp::CertificateChain::List all = _chain->root_to_leaf ();
823 dcp::CertificateChain::List::iterator j = all.begin ();
824 for (int k = 0; k < i; ++k) {
828 if (d->ShowModal () == wxID_OK) {
829 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
831 throw OpenFileError (wx_to_std (d->GetPath ()));
834 string const s = j->certificate (true);
835 fwrite (s.c_str(), 1, s.length(), f);
841 void update_certificate_list ()
843 _certificates->DeleteAllItems ();
845 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
846 BOOST_FOREACH (dcp::Certificate const & i, certs) {
849 _certificates->InsertItem (item);
850 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
853 _certificates->SetItem (n, 0, _("Root"));
854 } else if (n == (certs.size() - 1)) {
855 _certificates->SetItem (n, 0, _("Leaf"));
857 _certificates->SetItem (n, 0, _("Intermediate"));
864 void remake_certificates ()
866 shared_ptr<const dcp::CertificateChain> chain = _get ();
868 string subject_organization_name;
869 string subject_organizational_unit_name;
870 string root_common_name;
871 string intermediate_common_name;
872 string leaf_common_name;
874 dcp::CertificateChain::List all = chain->root_to_leaf ();
876 if (all.size() >= 1) {
878 subject_organization_name = chain->root().subject_organization_name ();
879 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
880 root_common_name = chain->root().subject_common_name ();
883 if (all.size() >= 2) {
885 leaf_common_name = chain->leaf().subject_common_name ();
888 if (all.size() >= 3) {
889 /* Have an intermediate */
890 dcp::CertificateChain::List::iterator i = all.begin ();
892 intermediate_common_name = i->subject_common_name ();
895 MakeChainDialog* d = new MakeChainDialog (
897 subject_organization_name,
898 subject_organizational_unit_name,
900 intermediate_common_name,
904 if (d->ShowModal () == wxID_OK) {
906 new dcp::CertificateChain (
909 d->organisational_unit (),
910 d->root_common_name (),
911 d->intermediate_common_name (),
912 d->leaf_common_name ()
917 update_certificate_list ();
918 update_private_key ();
924 void update_sensitivity ()
926 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
927 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
930 void update_private_key ()
932 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
936 void load_private_key ()
938 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
940 if (d->ShowModal() == wxID_OK) {
942 boost::filesystem::path p (wx_to_std (d->GetPath ()));
943 if (boost::filesystem::file_size (p) > 8192) {
946 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
951 _chain->set_key (dcp::file_to_string (p));
953 update_private_key ();
954 } catch (dcp::MiscError& e) {
955 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
961 update_sensitivity ();
964 void export_private_key ()
966 optional<string> key = _chain->key ();
971 wxFileDialog* d = new wxFileDialog (
972 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
973 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
976 if (d->ShowModal () == wxID_OK) {
977 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
979 throw OpenFileError (wx_to_std (d->GetPath ()));
982 string const s = _chain->key().get ();
983 fwrite (s.c_str(), 1, s.length(), f);
989 wxListCtrl* _certificates;
990 wxButton* _add_certificate;
991 wxButton* _export_certificate;
992 wxButton* _remove_certificate;
993 wxButton* _remake_certificates;
994 wxStaticText* _private_key;
995 wxButton* _load_private_key;
996 wxButton* _export_private_key;
998 wxBoxSizer* _button_sizer;
999 shared_ptr<dcp::CertificateChain> _chain;
1000 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1001 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1004 class KeysPage : public StandardPage
1007 KeysPage (wxSize panel_size, int border)
1008 : StandardPage (panel_size, border)
1011 wxString GetName () const
1016 #ifdef DCPOMATIC_OSX
1017 wxBitmap GetLargeIcon () const
1019 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1027 _signer = new CertificateChainEditor (
1028 _panel, _("Signing DCPs and KDMs"), _border,
1029 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1030 boost::bind (&Config::signer_chain, Config::instance ())
1033 _panel->GetSizer()->Add (_signer);
1035 _decryption = new CertificateChainEditor (
1036 _panel, _("Decrypting DCPs"), _border,
1037 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1038 boost::bind (&Config::decryption_chain, Config::instance ())
1041 _panel->GetSizer()->Add (_decryption);
1043 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1044 _decryption->add_button (_export_decryption_certificate);
1045 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1046 _decryption->add_button (_export_decryption_chain);
1048 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1049 _export_decryption_chain->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_chain, this));
1052 void export_decryption_certificate ()
1054 wxFileDialog* d = new wxFileDialog (
1055 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1056 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1059 if (d->ShowModal () == wxID_OK) {
1060 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1062 throw OpenFileError (wx_to_std (d->GetPath ()));
1065 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1066 fwrite (s.c_str(), 1, s.length(), f);
1072 void export_decryption_chain ()
1074 wxFileDialog* d = new wxFileDialog (
1075 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1076 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1079 if (d->ShowModal () == wxID_OK) {
1080 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1082 throw OpenFileError (wx_to_std (d->GetPath ()));
1085 string const s = Config::instance()->decryption_chain()->chain();
1086 fwrite (s.c_str(), 1, s.length(), f);
1092 void config_changed ()
1094 _signer->config_changed ();
1095 _decryption->config_changed ();
1098 CertificateChainEditor* _signer;
1099 CertificateChainEditor* _decryption;
1100 wxButton* _export_decryption_certificate;
1101 wxButton* _export_decryption_chain;
1104 class TMSPage : public StandardPage
1107 TMSPage (wxSize panel_size, int border)
1108 : StandardPage (panel_size, border)
1111 wxString GetName () const
1116 #ifdef DCPOMATIC_OSX
1117 wxBitmap GetLargeIcon () const
1119 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1126 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1127 table->AddGrowableCol (1, 1);
1128 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1130 add_label_to_sizer (table, _panel, _("Protocol"), true);
1131 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1132 table->Add (_tms_protocol, 1, wxEXPAND);
1134 add_label_to_sizer (table, _panel, _("IP address"), true);
1135 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1136 table->Add (_tms_ip, 1, wxEXPAND);
1138 add_label_to_sizer (table, _panel, _("Target path"), true);
1139 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1140 table->Add (_tms_path, 1, wxEXPAND);
1142 add_label_to_sizer (table, _panel, _("User name"), true);
1143 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1144 table->Add (_tms_user, 1, wxEXPAND);
1146 add_label_to_sizer (table, _panel, _("Password"), true);
1147 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1148 table->Add (_tms_password, 1, wxEXPAND);
1150 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1151 _tms_protocol->Append (_("FTP (for Dolby)"));
1153 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1154 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1155 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1156 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1157 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1160 void config_changed ()
1162 Config* config = Config::instance ();
1164 checked_set (_tms_protocol, config->tms_protocol ());
1165 checked_set (_tms_ip, config->tms_ip ());
1166 checked_set (_tms_path, config->tms_path ());
1167 checked_set (_tms_user, config->tms_user ());
1168 checked_set (_tms_password, config->tms_password ());
1171 void tms_protocol_changed ()
1173 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1176 void tms_ip_changed ()
1178 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1181 void tms_path_changed ()
1183 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1186 void tms_user_changed ()
1188 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1191 void tms_password_changed ()
1193 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1196 wxChoice* _tms_protocol;
1197 wxTextCtrl* _tms_ip;
1198 wxTextCtrl* _tms_path;
1199 wxTextCtrl* _tms_user;
1200 wxTextCtrl* _tms_password;
1209 class KDMEmailPage : public StandardPage
1213 KDMEmailPage (wxSize panel_size, int border)
1214 #ifdef DCPOMATIC_OSX
1215 /* We have to force both width and height of this one */
1216 : StandardPage (wxSize (480, 128), border)
1218 : StandardPage (panel_size, border)
1222 wxString GetName () const
1224 return _("KDM Email");
1227 #ifdef DCPOMATIC_OSX
1228 wxBitmap GetLargeIcon () const
1230 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1237 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1238 table->AddGrowableCol (1, 1);
1239 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1241 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1243 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1244 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1245 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1246 add_label_to_sizer (s, _panel, _("port"), false);
1247 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1248 _mail_port->SetRange (0, 65535);
1249 s->Add (_mail_port);
1250 table->Add (s, 1, wxEXPAND | wxALL);
1253 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1254 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1255 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1257 add_label_to_sizer (table, _panel, _("Mail password"), true);
1258 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1259 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1261 add_label_to_sizer (table, _panel, _("Subject"), true);
1262 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1263 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1265 add_label_to_sizer (table, _panel, _("From address"), true);
1266 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1267 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1269 vector<string> columns;
1270 columns.push_back (wx_to_std (_("Address")));
1271 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1272 _kdm_cc = new EditableList<string, EmailDialog> (
1275 bind (&Config::kdm_cc, Config::instance()),
1276 bind (&Config::set_kdm_cc, Config::instance(), _1),
1277 bind (&string_not_empty, _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 titles['i'] = "unique ID";
1443 titles['c'] = "content filename";
1444 dcp::NameFormat::Map examples;
1445 examples['t'] = "cpl";
1446 examples['i'] = "eb1c112c-ca3c-4ae6-9263-c6714ff05d64";
1447 examples['c'] = "myfile.mp4";
1448 _dcp_metadata_filename_format = new NameFormatEditor (_panel, Config::instance()->dcp_metadata_filename_format(), titles, examples);
1449 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1453 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1454 dcp::NameFormat::Map titles;
1455 titles['t'] = "type (j2c/pcm/sub)";
1456 titles['i'] = "unique ID";
1457 titles['r'] = "reel number";
1458 titles['n'] = "number of reels";
1459 titles['c'] = "content filename";
1460 dcp::NameFormat::Map examples;
1461 examples['t'] = "j2c";
1462 examples['i'] = "eb1c112c-ca3c-4ae6-9263-c6714ff05d64";
1463 examples['r'] = "1";
1464 examples['n'] = "4";
1465 examples['c'] = "myfile.mp4";
1466 _dcp_asset_filename_format = new NameFormatEditor (_panel, Config::instance()->dcp_asset_filename_format(), titles, examples);
1467 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1471 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1472 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1473 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1474 t->Add (_log_general, 1, wxEXPAND | wxALL);
1475 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1476 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1477 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1478 t->Add (_log_error, 1, wxEXPAND | wxALL);
1479 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1480 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1481 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1482 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1483 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1484 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1485 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1486 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1487 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1488 table->Add (t, 0, wxALL, 6);
1491 #ifdef DCPOMATIC_WINDOWS
1492 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1493 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1494 table->AddSpacer (0);
1497 _maximum_j2k_bandwidth->SetRange (1, 1000);
1498 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1499 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1500 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1501 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1502 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1503 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1504 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1505 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1506 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1507 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1508 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1509 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1510 #ifdef DCPOMATIC_WINDOWS
1511 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1515 void config_changed ()
1517 Config* config = Config::instance ();
1519 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1520 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1521 checked_set (_only_servers_encode, config->only_servers_encode ());
1522 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1523 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1524 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1525 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1526 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1527 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1528 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1529 #ifdef DCPOMATIC_WINDOWS
1530 checked_set (_win32_console, config->win32_console());
1534 void maximum_j2k_bandwidth_changed ()
1536 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1539 void allow_any_dcp_frame_rate_changed ()
1541 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1544 void only_servers_encode_changed ()
1546 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1549 void dcp_metadata_filename_format_changed ()
1551 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1554 void dcp_asset_filename_format_changed ()
1556 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1562 if (_log_general->GetValue ()) {
1563 types |= LogEntry::TYPE_GENERAL;
1565 if (_log_warning->GetValue ()) {
1566 types |= LogEntry::TYPE_WARNING;
1568 if (_log_error->GetValue ()) {
1569 types |= LogEntry::TYPE_ERROR;
1571 if (_log_timing->GetValue ()) {
1572 types |= LogEntry::TYPE_TIMING;
1574 if (_log_debug_decode->GetValue ()) {
1575 types |= LogEntry::TYPE_DEBUG_DECODE;
1577 if (_log_debug_encode->GetValue ()) {
1578 types |= LogEntry::TYPE_DEBUG_ENCODE;
1580 if (_log_debug_email->GetValue ()) {
1581 types |= LogEntry::TYPE_DEBUG_EMAIL;
1583 Config::instance()->set_log_types (types);
1586 #ifdef DCPOMATIC_WINDOWS
1587 void win32_console_changed ()
1589 Config::instance()->set_win32_console (_win32_console->GetValue ());
1593 wxSpinCtrl* _maximum_j2k_bandwidth;
1594 wxCheckBox* _allow_any_dcp_frame_rate;
1595 wxCheckBox* _only_servers_encode;
1596 NameFormatEditor* _dcp_metadata_filename_format;
1597 NameFormatEditor* _dcp_asset_filename_format;
1598 wxCheckBox* _log_general;
1599 wxCheckBox* _log_warning;
1600 wxCheckBox* _log_error;
1601 wxCheckBox* _log_timing;
1602 wxCheckBox* _log_debug_decode;
1603 wxCheckBox* _log_debug_encode;
1604 wxCheckBox* _log_debug_email;
1605 #ifdef DCPOMATIC_WINDOWS
1606 wxCheckBox* _win32_console;
1610 wxPreferencesEditor*
1611 create_config_dialog ()
1613 wxPreferencesEditor* e = new wxPreferencesEditor ();
1615 #ifdef DCPOMATIC_OSX
1616 /* Width that we force some of the config panels to be on OSX so that
1617 the containing window doesn't shrink too much when we select those panels.
1618 This is obviously an unpleasant hack.
1620 wxSize ps = wxSize (520, -1);
1621 int const border = 16;
1623 wxSize ps = wxSize (-1, -1);
1624 int const border = 8;
1627 e->AddPage (new GeneralPage (ps, border));
1628 e->AddPage (new DefaultsPage (ps, border));
1629 e->AddPage (new EncodingServersPage (ps, border));
1630 e->AddPage (new KeysPage (ps, border));
1631 e->AddPage (new TMSPage (ps, border));
1632 e->AddPage (new KDMEmailPage (ps, border));
1633 e->AddPage (new AdvancedPage (ps, border));