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/raw_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::raw_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, raw_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 (dcp::raw_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s))));
543 void directory_changed ()
545 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
548 void edit_isdcf_metadata_clicked ()
550 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
552 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
556 void still_length_changed ()
558 Config::instance()->set_default_still_length (_still_length->GetValue ());
561 void container_changed ()
563 vector<Ratio const *> ratio = Ratio::all ();
564 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
567 void dcp_content_type_changed ()
569 vector<DCPContentType const *> ct = DCPContentType::all ();
570 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
573 void standard_changed ()
575 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
578 wxSpinCtrl* _j2k_bandwidth;
579 wxSpinCtrl* _audio_delay;
580 wxButton* _isdcf_metadata_button;
581 wxSpinCtrl* _still_length;
582 #ifdef DCPOMATIC_USE_OWN_PICKER
583 DirPickerCtrl* _directory;
585 wxDirPickerCtrl* _directory;
587 wxChoice* _container;
588 wxChoice* _dcp_content_type;
589 wxChoice* _dcp_audio_channels;
593 class EncodingServersPage : public StandardPage
596 EncodingServersPage (wxSize panel_size, int border)
597 : StandardPage (panel_size, border)
600 wxString GetName () const
606 wxBitmap GetLargeIcon () const
608 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
615 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
616 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
618 vector<string> columns;
619 columns.push_back (wx_to_std (_("IP address / host name")));
620 _servers_list = new EditableList<string, ServerDialog> (
623 boost::bind (&Config::servers, Config::instance()),
624 boost::bind (&Config::set_servers, Config::instance(), _1),
625 boost::bind (&always_valid),
626 boost::bind (&EncodingServersPage::server_column, this, _1)
629 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
631 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
634 void config_changed ()
636 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
637 _servers_list->refresh ();
640 void use_any_servers_changed ()
642 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
645 string server_column (string s)
650 wxCheckBox* _use_any_servers;
651 EditableList<string, ServerDialog>* _servers_list;
654 class CertificateChainEditor : public wxPanel
657 CertificateChainEditor (
661 function<void (shared_ptr<dcp::CertificateChain>)> set,
662 function<shared_ptr<const dcp::CertificateChain> (void)> get
668 wxFont subheading_font (*wxNORMAL_FONT);
669 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
671 _sizer = new wxBoxSizer (wxVERTICAL);
674 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
675 m->SetFont (subheading_font);
676 _sizer->Add (m, 0, wxALL, border);
679 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
680 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
682 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
687 ip.SetText (_("Type"));
689 _certificates->InsertColumn (0, ip);
695 ip.SetText (_("Thumbprint"));
698 wxFont font = ip.GetFont ();
699 font.SetFamily (wxFONTFAMILY_TELETYPE);
702 _certificates->InsertColumn (1, ip);
705 certificates_sizer->Add (_certificates, 1, wxEXPAND);
708 wxSizer* s = new wxBoxSizer (wxVERTICAL);
709 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
710 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
711 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
712 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
713 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
714 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
715 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
718 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
719 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
722 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
723 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
724 wxFont font = _private_key->GetFont ();
725 font.SetFamily (wxFONTFAMILY_TELETYPE);
726 _private_key->SetFont (font);
727 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
728 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
729 table->Add (_load_private_key, wxGBPosition (r, 2));
730 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
731 table->Add (_export_private_key, wxGBPosition (r, 3));
734 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
735 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
736 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
737 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
740 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::add_certificate, this));
741 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remove_certificate, this));
742 _export_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_certificate, this));
743 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
744 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
745 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remake_certificates, this));
746 _load_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::load_private_key, this));
747 _export_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_private_key, this));
749 SetSizerAndFit (_sizer);
752 void config_changed ()
754 _chain.reset (new dcp::CertificateChain (*_get().get ()));
756 update_certificate_list ();
757 update_private_key ();
758 update_sensitivity ();
761 void add_button (wxWindow* button)
763 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
768 void add_certificate ()
770 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
772 if (d->ShowModal() == wxID_OK) {
774 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
775 if (c.extra_data ()) {
778 _("This file contains other certificates (or other data) after its first certificate. "
779 "Only the first certificate will be used.")
784 update_certificate_list ();
785 } catch (dcp::MiscError& e) {
786 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
792 update_sensitivity ();
795 void remove_certificate ()
797 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
802 _certificates->DeleteItem (i);
806 update_sensitivity ();
809 void export_certificate ()
811 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
816 wxFileDialog* d = new wxFileDialog (
817 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
818 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
821 dcp::CertificateChain::List all = _chain->root_to_leaf ();
822 dcp::CertificateChain::List::iterator j = all.begin ();
823 for (int k = 0; k < i; ++k) {
827 if (d->ShowModal () == wxID_OK) {
828 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
830 throw OpenFileError (wx_to_std (d->GetPath ()));
833 string const s = j->certificate (true);
834 fwrite (s.c_str(), 1, s.length(), f);
840 void update_certificate_list ()
842 _certificates->DeleteAllItems ();
844 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
845 BOOST_FOREACH (dcp::Certificate const & i, certs) {
848 _certificates->InsertItem (item);
849 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
852 _certificates->SetItem (n, 0, _("Root"));
853 } else if (n == (certs.size() - 1)) {
854 _certificates->SetItem (n, 0, _("Leaf"));
856 _certificates->SetItem (n, 0, _("Intermediate"));
863 void remake_certificates ()
865 shared_ptr<const dcp::CertificateChain> chain = _get ();
867 string subject_organization_name;
868 string subject_organizational_unit_name;
869 string root_common_name;
870 string intermediate_common_name;
871 string leaf_common_name;
873 dcp::CertificateChain::List all = chain->root_to_leaf ();
875 if (all.size() >= 1) {
877 subject_organization_name = chain->root().subject_organization_name ();
878 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
879 root_common_name = chain->root().subject_common_name ();
882 if (all.size() >= 2) {
884 leaf_common_name = chain->leaf().subject_common_name ();
887 if (all.size() >= 3) {
888 /* Have an intermediate */
889 dcp::CertificateChain::List::iterator i = all.begin ();
891 intermediate_common_name = i->subject_common_name ();
894 MakeChainDialog* d = new MakeChainDialog (
896 subject_organization_name,
897 subject_organizational_unit_name,
899 intermediate_common_name,
903 if (d->ShowModal () == wxID_OK) {
905 new dcp::CertificateChain (
908 d->organisational_unit (),
909 d->root_common_name (),
910 d->intermediate_common_name (),
911 d->leaf_common_name ()
916 update_certificate_list ();
917 update_private_key ();
923 void update_sensitivity ()
925 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
926 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
929 void update_private_key ()
931 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
935 void load_private_key ()
937 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
939 if (d->ShowModal() == wxID_OK) {
941 boost::filesystem::path p (wx_to_std (d->GetPath ()));
942 if (boost::filesystem::file_size (p) > 8192) {
945 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
950 _chain->set_key (dcp::file_to_string (p));
952 update_private_key ();
953 } catch (dcp::MiscError& e) {
954 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
960 update_sensitivity ();
963 void export_private_key ()
965 optional<string> key = _chain->key ();
970 wxFileDialog* d = new wxFileDialog (
971 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
972 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
975 if (d->ShowModal () == wxID_OK) {
976 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
978 throw OpenFileError (wx_to_std (d->GetPath ()));
981 string const s = _chain->key().get ();
982 fwrite (s.c_str(), 1, s.length(), f);
988 wxListCtrl* _certificates;
989 wxButton* _add_certificate;
990 wxButton* _export_certificate;
991 wxButton* _remove_certificate;
992 wxButton* _remake_certificates;
993 wxStaticText* _private_key;
994 wxButton* _load_private_key;
995 wxButton* _export_private_key;
997 wxBoxSizer* _button_sizer;
998 shared_ptr<dcp::CertificateChain> _chain;
999 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1000 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1003 class KeysPage : public StandardPage
1006 KeysPage (wxSize panel_size, int border)
1007 : StandardPage (panel_size, border)
1010 wxString GetName () const
1015 #ifdef DCPOMATIC_OSX
1016 wxBitmap GetLargeIcon () const
1018 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1026 _signer = new CertificateChainEditor (
1027 _panel, _("Signing DCPs and KDMs"), _border,
1028 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1029 boost::bind (&Config::signer_chain, Config::instance ())
1032 _panel->GetSizer()->Add (_signer);
1034 _decryption = new CertificateChainEditor (
1035 _panel, _("Decrypting DCPs"), _border,
1036 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1037 boost::bind (&Config::decryption_chain, Config::instance ())
1040 _panel->GetSizer()->Add (_decryption);
1042 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\ncertificate..."));
1043 _decryption->add_button (_export_decryption_certificate);
1044 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption\nchain..."));
1045 _decryption->add_button (_export_decryption_chain);
1047 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1048 _export_decryption_chain->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_chain, this));
1051 void export_decryption_certificate ()
1053 wxFileDialog* d = new wxFileDialog (
1054 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1055 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1058 if (d->ShowModal () == wxID_OK) {
1059 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1061 throw OpenFileError (wx_to_std (d->GetPath ()));
1064 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1065 fwrite (s.c_str(), 1, s.length(), f);
1071 void export_decryption_chain ()
1073 wxFileDialog* d = new wxFileDialog (
1074 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1075 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1078 if (d->ShowModal () == wxID_OK) {
1079 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1081 throw OpenFileError (wx_to_std (d->GetPath ()));
1084 string const s = Config::instance()->decryption_chain()->chain();
1085 fwrite (s.c_str(), 1, s.length(), f);
1091 void config_changed ()
1093 _signer->config_changed ();
1094 _decryption->config_changed ();
1097 CertificateChainEditor* _signer;
1098 CertificateChainEditor* _decryption;
1099 wxButton* _export_decryption_certificate;
1100 wxButton* _export_decryption_chain;
1103 class TMSPage : public StandardPage
1106 TMSPage (wxSize panel_size, int border)
1107 : StandardPage (panel_size, border)
1110 wxString GetName () const
1115 #ifdef DCPOMATIC_OSX
1116 wxBitmap GetLargeIcon () const
1118 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1125 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1126 table->AddGrowableCol (1, 1);
1127 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1129 add_label_to_sizer (table, _panel, _("Protocol"), true);
1130 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1131 table->Add (_tms_protocol, 1, wxEXPAND);
1133 add_label_to_sizer (table, _panel, _("IP address"), true);
1134 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1135 table->Add (_tms_ip, 1, wxEXPAND);
1137 add_label_to_sizer (table, _panel, _("Target path"), true);
1138 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1139 table->Add (_tms_path, 1, wxEXPAND);
1141 add_label_to_sizer (table, _panel, _("User name"), true);
1142 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1143 table->Add (_tms_user, 1, wxEXPAND);
1145 add_label_to_sizer (table, _panel, _("Password"), true);
1146 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1147 table->Add (_tms_password, 1, wxEXPAND);
1149 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1150 _tms_protocol->Append (_("FTP (for Dolby)"));
1152 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1153 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1154 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1155 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1156 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1159 void config_changed ()
1161 Config* config = Config::instance ();
1163 checked_set (_tms_protocol, config->tms_protocol ());
1164 checked_set (_tms_ip, config->tms_ip ());
1165 checked_set (_tms_path, config->tms_path ());
1166 checked_set (_tms_user, config->tms_user ());
1167 checked_set (_tms_password, config->tms_password ());
1170 void tms_protocol_changed ()
1172 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1175 void tms_ip_changed ()
1177 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1180 void tms_path_changed ()
1182 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1185 void tms_user_changed ()
1187 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1190 void tms_password_changed ()
1192 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1195 wxChoice* _tms_protocol;
1196 wxTextCtrl* _tms_ip;
1197 wxTextCtrl* _tms_path;
1198 wxTextCtrl* _tms_user;
1199 wxTextCtrl* _tms_password;
1208 class KDMEmailPage : public StandardPage
1212 KDMEmailPage (wxSize panel_size, int border)
1213 #ifdef DCPOMATIC_OSX
1214 /* We have to force both width and height of this one */
1215 : StandardPage (wxSize (480, 128), border)
1217 : StandardPage (panel_size, border)
1221 wxString GetName () const
1223 return _("KDM Email");
1226 #ifdef DCPOMATIC_OSX
1227 wxBitmap GetLargeIcon () const
1229 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1236 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1237 table->AddGrowableCol (1, 1);
1238 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1240 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1242 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1243 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1244 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1245 add_label_to_sizer (s, _panel, _("port"), false);
1246 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1247 _mail_port->SetRange (0, 65535);
1248 s->Add (_mail_port);
1249 table->Add (s, 1, wxEXPAND | wxALL);
1252 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1253 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1254 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1256 add_label_to_sizer (table, _panel, _("Mail password"), true);
1257 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1258 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1260 add_label_to_sizer (table, _panel, _("Subject"), true);
1261 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1262 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1264 add_label_to_sizer (table, _panel, _("From address"), true);
1265 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1266 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1268 vector<string> columns;
1269 columns.push_back (wx_to_std (_("Address")));
1270 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1271 _kdm_cc = new EditableList<string, EmailDialog> (
1274 bind (&Config::kdm_cc, Config::instance()),
1275 bind (&Config::set_kdm_cc, Config::instance(), _1),
1276 bind (&string_not_empty, _1),
1279 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1281 add_label_to_sizer (table, _panel, _("BCC address"), true);
1282 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1283 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1285 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1286 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1288 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1289 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1293 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1294 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1295 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1296 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1297 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1298 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1299 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1300 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1301 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1304 void config_changed ()
1306 Config* config = Config::instance ();
1308 checked_set (_mail_server, config->mail_server ());
1309 checked_set (_mail_port, config->mail_port ());
1310 checked_set (_mail_user, config->mail_user ());
1311 checked_set (_mail_password, config->mail_password ());
1312 checked_set (_kdm_subject, config->kdm_subject ());
1313 checked_set (_kdm_from, config->kdm_from ());
1314 checked_set (_kdm_bcc, config->kdm_bcc ());
1315 checked_set (_kdm_email, Config::instance()->kdm_email ());
1318 void mail_server_changed ()
1320 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1323 void mail_port_changed ()
1325 Config::instance()->set_mail_port (_mail_port->GetValue ());
1328 void mail_user_changed ()
1330 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1333 void mail_password_changed ()
1335 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1338 void kdm_subject_changed ()
1340 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1343 void kdm_from_changed ()
1345 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1348 void kdm_bcc_changed ()
1350 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1353 void kdm_email_changed ()
1355 if (_kdm_email->GetValue().IsEmpty ()) {
1356 /* Sometimes we get sent an erroneous notification that the email
1357 is empty; I don't know why.
1361 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1364 void reset_kdm_email ()
1366 Config::instance()->reset_kdm_email ();
1367 checked_set (_kdm_email, Config::instance()->kdm_email ());
1370 wxTextCtrl* _mail_server;
1371 wxSpinCtrl* _mail_port;
1372 wxTextCtrl* _mail_user;
1373 wxTextCtrl* _mail_password;
1374 wxTextCtrl* _kdm_subject;
1375 wxTextCtrl* _kdm_from;
1376 EditableList<string, EmailDialog>* _kdm_cc;
1377 wxTextCtrl* _kdm_bcc;
1378 wxTextCtrl* _kdm_email;
1379 wxButton* _reset_kdm_email;
1382 /** @class AdvancedPage
1383 * @brief Advanced page of the preferences dialog.
1385 class AdvancedPage : public StockPage
1388 AdvancedPage (wxSize panel_size, int border)
1389 : StockPage (Kind_Advanced, panel_size, border)
1390 , _maximum_j2k_bandwidth (0)
1391 , _allow_any_dcp_frame_rate (0)
1392 , _only_servers_encode (0)
1397 , _log_debug_decode (0)
1398 , _log_debug_encode (0)
1399 , _log_debug_email (0)
1403 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1405 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1407 flags |= wxALIGN_RIGHT;
1410 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1411 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1416 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1417 table->AddGrowableCol (1, 1);
1418 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1421 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1422 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1423 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1424 s->Add (_maximum_j2k_bandwidth, 1);
1425 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1429 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1430 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1431 table->AddSpacer (0);
1433 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1434 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1435 table->AddSpacer (0);
1438 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1439 dcp::NameFormat::Map titles;
1440 titles['t'] = "type (cpl/pkl)";
1441 titles['i'] = "unique ID";
1442 titles['c'] = "content filename";
1443 dcp::NameFormat::Map examples;
1444 examples['t'] = "cpl";
1445 examples['i'] = "eb1c112c-ca3c-4ae6-9263-c6714ff05d64";
1446 examples['c'] = "myfile.mp4";
1447 _dcp_metadata_filename_format = new NameFormatEditor (_panel, Config::instance()->dcp_metadata_filename_format(), titles, examples);
1448 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1452 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1453 dcp::NameFormat::Map titles;
1454 titles['t'] = "type (j2c/pcm/sub)";
1455 titles['i'] = "unique ID";
1456 titles['r'] = "reel number";
1457 titles['n'] = "number of reels";
1458 titles['c'] = "content filename";
1459 dcp::NameFormat::Map examples;
1460 examples['t'] = "j2c";
1461 examples['i'] = "eb1c112c-ca3c-4ae6-9263-c6714ff05d64";
1462 examples['r'] = "1";
1463 examples['n'] = "4";
1464 examples['c'] = "myfile.mp4";
1465 _dcp_asset_filename_format = new NameFormatEditor (_panel, Config::instance()->dcp_asset_filename_format(), titles, examples);
1466 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1470 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1471 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1472 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1473 t->Add (_log_general, 1, wxEXPAND | wxALL);
1474 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1475 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1476 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1477 t->Add (_log_error, 1, wxEXPAND | wxALL);
1478 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1479 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1480 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1481 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1482 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1483 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1484 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1485 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1486 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1487 table->Add (t, 0, wxALL, 6);
1490 #ifdef DCPOMATIC_WINDOWS
1491 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1492 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1493 table->AddSpacer (0);
1496 _maximum_j2k_bandwidth->SetRange (1, 1000);
1497 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1498 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1499 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1500 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1501 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1502 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1503 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1504 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1505 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1506 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1507 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1508 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1509 #ifdef DCPOMATIC_WINDOWS
1510 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1514 void config_changed ()
1516 Config* config = Config::instance ();
1518 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1519 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1520 checked_set (_only_servers_encode, config->only_servers_encode ());
1521 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1522 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1523 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1524 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1525 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1526 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1527 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1528 #ifdef DCPOMATIC_WINDOWS
1529 checked_set (_win32_console, config->win32_console());
1533 void maximum_j2k_bandwidth_changed ()
1535 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1538 void allow_any_dcp_frame_rate_changed ()
1540 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1543 void only_servers_encode_changed ()
1545 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1548 void dcp_metadata_filename_format_changed ()
1550 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1553 void dcp_asset_filename_format_changed ()
1555 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1561 if (_log_general->GetValue ()) {
1562 types |= LogEntry::TYPE_GENERAL;
1564 if (_log_warning->GetValue ()) {
1565 types |= LogEntry::TYPE_WARNING;
1567 if (_log_error->GetValue ()) {
1568 types |= LogEntry::TYPE_ERROR;
1570 if (_log_timing->GetValue ()) {
1571 types |= LogEntry::TYPE_TIMING;
1573 if (_log_debug_decode->GetValue ()) {
1574 types |= LogEntry::TYPE_DEBUG_DECODE;
1576 if (_log_debug_encode->GetValue ()) {
1577 types |= LogEntry::TYPE_DEBUG_ENCODE;
1579 if (_log_debug_email->GetValue ()) {
1580 types |= LogEntry::TYPE_DEBUG_EMAIL;
1582 Config::instance()->set_log_types (types);
1585 #ifdef DCPOMATIC_WINDOWS
1586 void win32_console_changed ()
1588 Config::instance()->set_win32_console (_win32_console->GetValue ());
1592 wxSpinCtrl* _maximum_j2k_bandwidth;
1593 wxCheckBox* _allow_any_dcp_frame_rate;
1594 wxCheckBox* _only_servers_encode;
1595 NameFormatEditor* _dcp_metadata_filename_format;
1596 NameFormatEditor* _dcp_asset_filename_format;
1597 wxCheckBox* _log_general;
1598 wxCheckBox* _log_warning;
1599 wxCheckBox* _log_error;
1600 wxCheckBox* _log_timing;
1601 wxCheckBox* _log_debug_decode;
1602 wxCheckBox* _log_debug_encode;
1603 wxCheckBox* _log_debug_email;
1604 #ifdef DCPOMATIC_WINDOWS
1605 wxCheckBox* _win32_console;
1609 wxPreferencesEditor*
1610 create_config_dialog ()
1612 wxPreferencesEditor* e = new wxPreferencesEditor ();
1614 #ifdef DCPOMATIC_OSX
1615 /* Width that we force some of the config panels to be on OSX so that
1616 the containing window doesn't shrink too much when we select those panels.
1617 This is obviously an unpleasant hack.
1619 wxSize ps = wxSize (520, -1);
1620 int const border = 16;
1622 wxSize ps = wxSize (-1, -1);
1623 int const border = 8;
1626 e->AddPage (new GeneralPage (ps, border));
1627 e->AddPage (new DefaultsPage (ps, border));
1628 e->AddPage (new EncodingServersPage (ps, border));
1629 e->AddPage (new KeysPage (ps, border));
1630 e->AddPage (new TMSPage (ps, border));
1631 e->AddPage (new KDMEmailPage (ps, border));
1632 e->AddPage (new AdvancedPage (ps, border));