2 Copyright (C) 2012-2017 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/full_config_dialog.cc
22 * @brief A dialogue to edit all DCP-o-matic configuration.
25 #include "full_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 "nag_dialog.h"
37 #include "config_move_dialog.h"
38 #include "config_dialog.h"
39 #include "lib/config.h"
40 #include "lib/ratio.h"
41 #include "lib/filter.h"
42 #include "lib/dcp_content_type.h"
45 #include "lib/cross.h"
46 #include "lib/exceptions.h"
47 #include <dcp/locale_convert.h>
48 #include <dcp/exceptions.h>
49 #include <dcp/certificate_chain.h>
50 #include <wx/stdpaths.h>
51 #include <wx/preferences.h>
52 #include <wx/spinctrl.h>
53 #include <wx/filepicker.h>
55 #include <boost/filesystem.hpp>
56 #include <boost/foreach.hpp>
67 using boost::shared_ptr;
68 using boost::function;
69 using boost::optional;
70 using dcp::locale_convert;
79 class FullGeneralPage : public GeneralPage
82 FullGeneralPage (wxSize panel_size, int border)
83 : GeneralPage (panel_size, border)
89 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
90 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
93 add_language_controls (table, r);
95 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
96 _master_encoding_threads = new wxSpinCtrl (_panel);
97 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
100 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
101 _server_encoding_threads = new wxSpinCtrl (_panel);
102 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
105 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
106 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true);
107 table->Add (_config_file, wxGBPosition (r, 1));
110 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
111 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true);
112 table->Add (_cinemas_file, wxGBPosition (r, 1));
115 add_play_sound_controls (table, r);
117 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
118 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
119 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
123 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
124 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
127 add_update_controls (table, r);
129 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
130 bottom_table->AddGrowableCol (1, 1);
132 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
133 _issuer = new wxTextCtrl (_panel, wxID_ANY);
134 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
136 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
137 _creator = new wxTextCtrl (_panel, wxID_ANY);
138 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
140 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
143 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::config_file_changed, this));
144 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::cinemas_file_changed, this));
146 _master_encoding_threads->SetRange (1, 128);
147 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
148 _server_encoding_threads->SetRange (1, 128);
149 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
151 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
152 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
154 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
156 _issuer->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::issuer_changed, this));
157 _creator->Bind (wxEVT_TEXT, boost::bind (&FullGeneralPage::creator_changed, this));
160 void config_changed ()
162 Config* config = Config::instance ();
164 checked_set (_master_encoding_threads, config->master_encoding_threads ());
165 checked_set (_server_encoding_threads, config->server_encoding_threads ());
166 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
167 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
169 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
170 checked_set (_issuer, config->dcp_issuer ());
171 checked_set (_creator, config->dcp_creator ());
172 checked_set (_config_file, config->config_file());
173 checked_set (_cinemas_file, config->cinemas_file());
175 GeneralPage::config_changed ();
179 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
180 void analyse_ebur128_changed ()
182 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
186 void automatic_audio_analysis_changed ()
188 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
191 void master_encoding_threads_changed ()
193 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue ());
196 void server_encoding_threads_changed ()
198 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue ());
201 void issuer_changed ()
203 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
206 void creator_changed ()
208 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
211 void config_file_changed ()
213 Config* config = Config::instance();
214 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
215 if (new_file == config->config_file()) {
218 bool copy_and_link = true;
219 if (boost::filesystem::exists(new_file)) {
220 ConfigMoveDialog* d = new ConfigMoveDialog (_panel, new_file);
221 if (d->ShowModal() == wxID_OK) {
222 copy_and_link = false;
229 if (new_file != config->config_file()) {
230 config->copy_and_link (new_file);
233 config->link (new_file);
237 void cinemas_file_changed ()
239 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
242 wxSpinCtrl* _master_encoding_threads;
243 wxSpinCtrl* _server_encoding_threads;
244 FilePickerCtrl* _config_file;
245 FilePickerCtrl* _cinemas_file;
246 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
247 wxCheckBox* _analyse_ebur128;
249 wxCheckBox* _automatic_audio_analysis;
251 wxTextCtrl* _creator;
254 class DefaultsPage : public StandardPage
257 DefaultsPage (wxSize panel_size, int border)
258 : StandardPage (panel_size, border)
261 wxString GetName () const
263 return _("Defaults");
267 wxBitmap GetLargeIcon () const
269 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
276 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
277 table->AddGrowableCol (1, 1);
278 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
281 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
282 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
283 _still_length = new wxSpinCtrl (_panel);
284 s->Add (_still_length);
285 add_label_to_sizer (s, _panel, _("s"), false);
289 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
290 #ifdef DCPOMATIC_USE_OWN_PICKER
291 _directory = new DirPickerCtrl (_panel);
293 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
295 table->Add (_directory, 1, wxEXPAND);
297 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
298 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
299 table->Add (_isdcf_metadata_button);
301 add_label_to_sizer (table, _panel, _("Default container"), true);
302 _container = new wxChoice (_panel, wxID_ANY);
303 table->Add (_container);
305 add_label_to_sizer (table, _panel, _("Default scale-to"), true);
306 _scale_to = new wxChoice (_panel, wxID_ANY);
307 table->Add (_scale_to);
309 add_label_to_sizer (table, _panel, _("Default content type"), true);
310 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
311 table->Add (_dcp_content_type);
313 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
314 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
315 table->Add (_dcp_audio_channels);
318 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
319 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
320 _j2k_bandwidth = new wxSpinCtrl (_panel);
321 s->Add (_j2k_bandwidth);
322 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
327 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
328 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
329 _audio_delay = new wxSpinCtrl (_panel);
330 s->Add (_audio_delay);
331 add_label_to_sizer (s, _panel, _("ms"), false);
335 add_label_to_sizer (table, _panel, _("Default standard"), true);
336 _standard = new wxChoice (_panel, wxID_ANY);
337 table->Add (_standard);
339 add_label_to_sizer (table, _panel, _("Default KDM directory"), true);
340 #ifdef DCPOMATIC_USE_OWN_PICKER
341 _kdm_directory = new DirPickerCtrl (_panel);
343 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
345 table->Add (_kdm_directory, 1, wxEXPAND);
347 _still_length->SetRange (1, 3600);
348 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
350 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
351 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
353 _isdcf_metadata_button->Bind (wxEVT_BUTTON, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
355 BOOST_FOREACH (Ratio const * i, Ratio::containers()) {
356 _container->Append (std_to_wx(i->container_nickname()));
359 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
361 _scale_to->Append (_("Guess from content"));
363 BOOST_FOREACH (Ratio const * i, Ratio::all()) {
364 _scale_to->Append (std_to_wx(i->image_nickname()));
367 _scale_to->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::scale_to_changed, this));
369 BOOST_FOREACH (DCPContentType const * i, DCPContentType::all()) {
370 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
373 setup_audio_channels_choice (_dcp_audio_channels, 2);
375 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
376 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
378 _j2k_bandwidth->SetRange (50, 250);
379 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
381 _audio_delay->SetRange (-1000, 1000);
382 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
384 _standard->Append (_("SMPTE"));
385 _standard->Append (_("Interop"));
386 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
389 void config_changed ()
391 Config* config = Config::instance ();
393 vector<Ratio const *> containers = Ratio::containers ();
394 for (size_t i = 0; i < containers.size(); ++i) {
395 if (containers[i] == config->default_container ()) {
396 _container->SetSelection (i);
400 vector<Ratio const *> ratios = Ratio::all ();
401 for (size_t i = 0; i < ratios.size(); ++i) {
402 if (ratios[i] == config->default_scale_to ()) {
403 _scale_to->SetSelection (i + 1);
407 if (!config->default_scale_to()) {
408 _scale_to->SetSelection (0);
411 vector<DCPContentType const *> const ct = DCPContentType::all ();
412 for (size_t i = 0; i < ct.size(); ++i) {
413 if (ct[i] == config->default_dcp_content_type ()) {
414 _dcp_content_type->SetSelection (i);
418 checked_set (_still_length, config->default_still_length ());
419 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
420 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
421 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
422 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
423 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
424 checked_set (_audio_delay, config->default_audio_delay ());
425 checked_set (_standard, config->default_interop() ? 1 : 0);
428 void j2k_bandwidth_changed ()
430 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
433 void audio_delay_changed ()
435 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
438 void dcp_audio_channels_changed ()
440 int const s = _dcp_audio_channels->GetSelection ();
441 if (s != wxNOT_FOUND) {
442 Config::instance()->set_default_dcp_audio_channels (
443 locale_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s)))
448 void directory_changed ()
450 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
453 void kdm_directory_changed ()
455 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
458 void edit_isdcf_metadata_clicked ()
460 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
462 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
466 void still_length_changed ()
468 Config::instance()->set_default_still_length (_still_length->GetValue ());
471 void container_changed ()
473 vector<Ratio const *> ratio = Ratio::containers ();
474 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
477 void scale_to_changed ()
479 int const s = _scale_to->GetSelection ();
481 Config::instance()->set_default_scale_to (0);
483 vector<Ratio const *> ratio = Ratio::all ();
484 Config::instance()->set_default_scale_to (ratio[s - 1]);
488 void dcp_content_type_changed ()
490 vector<DCPContentType const *> ct = DCPContentType::all ();
491 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
494 void standard_changed ()
496 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
499 wxSpinCtrl* _j2k_bandwidth;
500 wxSpinCtrl* _audio_delay;
501 wxButton* _isdcf_metadata_button;
502 wxSpinCtrl* _still_length;
503 #ifdef DCPOMATIC_USE_OWN_PICKER
504 DirPickerCtrl* _directory;
505 DirPickerCtrl* _kdm_directory;
507 wxDirPickerCtrl* _directory;
508 wxDirPickerCtrl* _kdm_directory;
510 wxChoice* _container;
512 wxChoice* _dcp_content_type;
513 wxChoice* _dcp_audio_channels;
517 class EncodingServersPage : public StandardPage
520 EncodingServersPage (wxSize panel_size, int border)
521 : StandardPage (panel_size, border)
524 wxString GetName () const
530 wxBitmap GetLargeIcon () const
532 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
539 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
540 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
542 vector<string> columns;
543 columns.push_back (wx_to_std (_("IP address / host name")));
544 _servers_list = new EditableList<string, ServerDialog> (
547 boost::bind (&Config::servers, Config::instance()),
548 boost::bind (&Config::set_servers, Config::instance(), _1),
549 boost::bind (&EncodingServersPage::server_column, this, _1)
552 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
554 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
557 void config_changed ()
559 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
560 _servers_list->refresh ();
563 void use_any_servers_changed ()
565 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
568 string server_column (string s)
573 wxCheckBox* _use_any_servers;
574 EditableList<string, ServerDialog>* _servers_list;
577 class CertificateChainEditor : public wxPanel
580 CertificateChainEditor (
584 function<void (shared_ptr<dcp::CertificateChain>)> set,
585 function<shared_ptr<const dcp::CertificateChain> (void)> get,
586 function<void (void)> nag_remake
591 , _nag_remake (nag_remake)
593 wxFont subheading_font (*wxNORMAL_FONT);
594 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
596 _sizer = new wxBoxSizer (wxVERTICAL);
599 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
600 m->SetFont (subheading_font);
601 _sizer->Add (m, 0, wxALL, border);
604 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
605 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
607 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
612 ip.SetText (_("Type"));
614 _certificates->InsertColumn (0, ip);
620 ip.SetText (_("Thumbprint"));
623 wxFont font = ip.GetFont ();
624 font.SetFamily (wxFONTFAMILY_TELETYPE);
627 _certificates->InsertColumn (1, ip);
630 certificates_sizer->Add (_certificates, 1, wxEXPAND);
633 wxSizer* s = new wxBoxSizer (wxVERTICAL);
634 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
635 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
636 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
637 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
638 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
639 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
640 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
643 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
644 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
647 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
648 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
649 wxFont font = _private_key->GetFont ();
650 font.SetFamily (wxFONTFAMILY_TELETYPE);
651 _private_key->SetFont (font);
652 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
653 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
654 table->Add (_load_private_key, wxGBPosition (r, 2));
655 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
656 table->Add (_export_private_key, wxGBPosition (r, 3));
659 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
660 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
661 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
662 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
665 _private_key_bad = new wxStaticText (this, wxID_ANY, _("Leaf private key does not match leaf certificate!"));
666 font = *wxSMALL_FONT;
667 font.SetWeight (wxFONTWEIGHT_BOLD);
668 _private_key_bad->SetFont (font);
669 table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
672 _add_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::add_certificate, this));
673 _remove_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remove_certificate, this));
674 _export_certificate->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_certificate, this));
675 _certificates->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
676 _certificates->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
677 _remake_certificates->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::remake_certificates, this));
678 _load_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::load_private_key, this));
679 _export_private_key->Bind (wxEVT_BUTTON, boost::bind (&CertificateChainEditor::export_private_key, this));
681 SetSizerAndFit (_sizer);
684 void config_changed ()
686 _chain.reset (new dcp::CertificateChain (*_get().get ()));
688 update_certificate_list ();
689 update_private_key ();
690 update_sensitivity ();
693 void add_button (wxWindow* button)
695 _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
700 void add_certificate ()
702 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
704 if (d->ShowModal() == wxID_OK) {
709 extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
710 } catch (boost::filesystem::filesystem_error& e) {
711 error_dialog (this, wxString::Format (_("Could not load certificate (%s)"), d->GetPath().data()));
716 if (!extra.empty ()) {
719 _("This file contains other certificates (or other data) after its first certificate. "
720 "Only the first certificate will be used.")
724 if (!_chain->chain_valid ()) {
727 _("Adding this certificate would make the chain inconsistent, so it will not be added. "
728 "Add certificates in order from root to intermediate to leaf.")
733 update_certificate_list ();
735 } catch (dcp::MiscError& e) {
736 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
742 update_sensitivity ();
745 void remove_certificate ()
747 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
752 _certificates->DeleteItem (i);
756 update_sensitivity ();
759 void export_certificate ()
761 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
766 wxFileDialog* d = new wxFileDialog (
767 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
768 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
771 dcp::CertificateChain::List all = _chain->root_to_leaf ();
772 dcp::CertificateChain::List::iterator j = all.begin ();
773 for (int k = 0; k < i; ++k) {
777 if (d->ShowModal () == wxID_OK) {
778 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
780 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
783 string const s = j->certificate (true);
784 fwrite (s.c_str(), 1, s.length(), f);
790 void update_certificate_list ()
792 _certificates->DeleteAllItems ();
794 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
795 BOOST_FOREACH (dcp::Certificate const & i, certs) {
798 _certificates->InsertItem (item);
799 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
802 _certificates->SetItem (n, 0, _("Root"));
803 } else if (n == (certs.size() - 1)) {
804 _certificates->SetItem (n, 0, _("Leaf"));
806 _certificates->SetItem (n, 0, _("Intermediate"));
812 static wxColour normal = _private_key_bad->GetForegroundColour ();
814 if (_chain->private_key_valid ()) {
815 _private_key_bad->Hide ();
816 _private_key_bad->SetForegroundColour (normal);
818 _private_key_bad->Show ();
819 _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
823 void remake_certificates ()
825 shared_ptr<const dcp::CertificateChain> chain = _get ();
827 string subject_organization_name;
828 string subject_organizational_unit_name;
829 string root_common_name;
830 string intermediate_common_name;
831 string leaf_common_name;
833 dcp::CertificateChain::List all = chain->root_to_leaf ();
835 if (all.size() >= 1) {
837 subject_organization_name = chain->root().subject_organization_name ();
838 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
839 root_common_name = chain->root().subject_common_name ();
842 if (all.size() >= 2) {
844 leaf_common_name = chain->leaf().subject_common_name ();
847 if (all.size() >= 3) {
848 /* Have an intermediate */
849 dcp::CertificateChain::List::iterator i = all.begin ();
851 intermediate_common_name = i->subject_common_name ();
856 MakeChainDialog* d = new MakeChainDialog (
858 subject_organization_name,
859 subject_organizational_unit_name,
861 intermediate_common_name,
865 if (d->ShowModal () == wxID_OK) {
867 new dcp::CertificateChain (
870 d->organisational_unit (),
871 d->root_common_name (),
872 d->intermediate_common_name (),
873 d->leaf_common_name ()
878 update_certificate_list ();
879 update_private_key ();
885 void update_sensitivity ()
887 /* We can only remove the leaf certificate */
888 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
889 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
892 void update_private_key ()
894 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
898 void load_private_key ()
900 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
902 if (d->ShowModal() == wxID_OK) {
904 boost::filesystem::path p (wx_to_std (d->GetPath ()));
905 if (boost::filesystem::file_size (p) > 8192) {
908 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
913 _chain->set_key (dcp::file_to_string (p));
915 update_private_key ();
916 } catch (dcp::MiscError& e) {
917 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
923 update_sensitivity ();
926 void export_private_key ()
928 optional<string> key = _chain->key ();
933 wxFileDialog* d = new wxFileDialog (
934 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
935 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
938 if (d->ShowModal () == wxID_OK) {
939 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
941 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
944 string const s = _chain->key().get ();
945 fwrite (s.c_str(), 1, s.length(), f);
951 wxListCtrl* _certificates;
952 wxButton* _add_certificate;
953 wxButton* _export_certificate;
954 wxButton* _remove_certificate;
955 wxButton* _remake_certificates;
956 wxStaticText* _private_key;
957 wxButton* _load_private_key;
958 wxButton* _export_private_key;
959 wxStaticText* _private_key_bad;
961 wxBoxSizer* _button_sizer;
962 shared_ptr<dcp::CertificateChain> _chain;
963 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
964 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
965 boost::function<void (void)> _nag_remake;
968 class KeysPage : public StandardPage
971 KeysPage (wxSize panel_size, int border)
972 : StandardPage (panel_size, border)
975 wxString GetName () const
981 wxBitmap GetLargeIcon () const
983 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
991 _signer = new CertificateChainEditor (
992 _panel, _("Signing DCPs and KDMs"), _border,
993 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
994 boost::bind (&Config::signer_chain, Config::instance ()),
995 boost::bind (&do_nothing)
998 _panel->GetSizer()->Add (_signer);
1000 _decryption = new CertificateChainEditor (
1001 _panel, _("Decrypting KDMs"), _border,
1002 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1003 boost::bind (&Config::decryption_chain, Config::instance ()),
1004 boost::bind (&KeysPage::nag_remake_decryption_chain, this)
1007 _panel->GetSizer()->Add (_decryption);
1009 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\ncertificate..."));
1010 _decryption->add_button (_export_decryption_certificate);
1011 _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\nchain..."));
1012 _decryption->add_button (_export_decryption_chain);
1014 _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
1015 _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
1018 void export_decryption_certificate ()
1020 wxFileDialog* d = new wxFileDialog (
1021 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1022 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1025 if (d->ShowModal () == wxID_OK) {
1026 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1028 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1031 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1032 fwrite (s.c_str(), 1, s.length(), f);
1038 void export_decryption_chain ()
1040 wxFileDialog* d = new wxFileDialog (
1041 _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1042 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1045 if (d->ShowModal () == wxID_OK) {
1046 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1048 throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
1051 string const s = Config::instance()->decryption_chain()->chain();
1052 fwrite (s.c_str(), 1, s.length(), f);
1058 void config_changed ()
1060 _signer->config_changed ();
1061 _decryption->config_changed ();
1064 void nag_remake_decryption_chain ()
1066 NagDialog::maybe_nag (
1068 Config::NAG_REMAKE_DECRYPTION_CHAIN,
1069 _("If you continue with this operation you will no longer be able to use any DKDMs that you have created. Also, any KDMs that have been sent to you will become useless. Proceed with caution!")
1073 CertificateChainEditor* _signer;
1074 CertificateChainEditor* _decryption;
1075 wxButton* _export_decryption_certificate;
1076 wxButton* _export_decryption_chain;
1079 class TMSPage : public StandardPage
1082 TMSPage (wxSize panel_size, int border)
1083 : StandardPage (panel_size, border)
1086 wxString GetName () const
1091 #ifdef DCPOMATIC_OSX
1092 wxBitmap GetLargeIcon () const
1094 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1101 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1102 table->AddGrowableCol (1, 1);
1103 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1105 add_label_to_sizer (table, _panel, _("Protocol"), true);
1106 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1107 table->Add (_tms_protocol, 1, wxEXPAND);
1109 add_label_to_sizer (table, _panel, _("IP address"), true);
1110 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1111 table->Add (_tms_ip, 1, wxEXPAND);
1113 add_label_to_sizer (table, _panel, _("Target path"), true);
1114 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1115 table->Add (_tms_path, 1, wxEXPAND);
1117 add_label_to_sizer (table, _panel, _("User name"), true);
1118 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1119 table->Add (_tms_user, 1, wxEXPAND);
1121 add_label_to_sizer (table, _panel, _("Password"), true);
1122 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1123 table->Add (_tms_password, 1, wxEXPAND);
1125 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1126 _tms_protocol->Append (_("FTP (for Dolby)"));
1128 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
1129 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
1130 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
1131 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
1132 _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
1135 void config_changed ()
1137 Config* config = Config::instance ();
1139 checked_set (_tms_protocol, config->tms_protocol ());
1140 checked_set (_tms_ip, config->tms_ip ());
1141 checked_set (_tms_path, config->tms_path ());
1142 checked_set (_tms_user, config->tms_user ());
1143 checked_set (_tms_password, config->tms_password ());
1146 void tms_protocol_changed ()
1148 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1151 void tms_ip_changed ()
1153 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1156 void tms_path_changed ()
1158 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1161 void tms_user_changed ()
1163 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1166 void tms_password_changed ()
1168 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1171 wxChoice* _tms_protocol;
1172 wxTextCtrl* _tms_ip;
1173 wxTextCtrl* _tms_path;
1174 wxTextCtrl* _tms_user;
1175 wxTextCtrl* _tms_password;
1184 class KDMEmailPage : public StandardPage
1188 KDMEmailPage (wxSize panel_size, int border)
1189 #ifdef DCPOMATIC_OSX
1190 /* We have to force both width and height of this one */
1191 : StandardPage (wxSize (480, 128), border)
1193 : StandardPage (panel_size, border)
1197 wxString GetName () const
1199 return _("KDM Email");
1202 #ifdef DCPOMATIC_OSX
1203 wxBitmap GetLargeIcon () const
1205 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1212 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1213 table->AddGrowableCol (1, 1);
1214 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1216 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1218 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1219 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1220 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1221 add_label_to_sizer (s, _panel, _("port"), false);
1222 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1223 _mail_port->SetRange (0, 65535);
1224 s->Add (_mail_port);
1225 table->Add (s, 1, wxEXPAND | wxALL);
1228 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1229 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1230 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1232 add_label_to_sizer (table, _panel, _("Mail password"), true);
1233 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1234 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1236 add_label_to_sizer (table, _panel, _("Subject"), true);
1237 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1238 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1240 add_label_to_sizer (table, _panel, _("From address"), true);
1241 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1242 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1244 vector<string> columns;
1245 columns.push_back (wx_to_std (_("Address")));
1246 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1247 _kdm_cc = new EditableList<string, EmailDialog> (
1250 bind (&Config::kdm_cc, Config::instance()),
1251 bind (&Config::set_kdm_cc, Config::instance(), _1),
1254 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1256 add_label_to_sizer (table, _panel, _("BCC address"), true);
1257 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1258 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1260 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1261 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1263 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1264 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1268 _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
1269 _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
1270 _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
1271 _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
1272 _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1273 _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1274 _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1275 _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1276 _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1279 void config_changed ()
1281 Config* config = Config::instance ();
1283 checked_set (_mail_server, config->mail_server ());
1284 checked_set (_mail_port, config->mail_port ());
1285 checked_set (_mail_user, config->mail_user ());
1286 checked_set (_mail_password, config->mail_password ());
1287 checked_set (_kdm_subject, config->kdm_subject ());
1288 checked_set (_kdm_from, config->kdm_from ());
1289 checked_set (_kdm_bcc, config->kdm_bcc ());
1290 checked_set (_kdm_email, Config::instance()->kdm_email ());
1293 void mail_server_changed ()
1295 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1298 void mail_port_changed ()
1300 Config::instance()->set_mail_port (_mail_port->GetValue ());
1303 void mail_user_changed ()
1305 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1308 void mail_password_changed ()
1310 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1313 void kdm_subject_changed ()
1315 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1318 void kdm_from_changed ()
1320 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1323 void kdm_bcc_changed ()
1325 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1328 void kdm_email_changed ()
1330 if (_kdm_email->GetValue().IsEmpty ()) {
1331 /* Sometimes we get sent an erroneous notification that the email
1332 is empty; I don't know why.
1336 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1339 void reset_kdm_email ()
1341 Config::instance()->reset_kdm_email ();
1342 checked_set (_kdm_email, Config::instance()->kdm_email ());
1345 wxTextCtrl* _mail_server;
1346 wxSpinCtrl* _mail_port;
1347 wxTextCtrl* _mail_user;
1348 wxTextCtrl* _mail_password;
1349 wxTextCtrl* _kdm_subject;
1350 wxTextCtrl* _kdm_from;
1351 EditableList<string, EmailDialog>* _kdm_cc;
1352 wxTextCtrl* _kdm_bcc;
1353 wxTextCtrl* _kdm_email;
1354 wxButton* _reset_kdm_email;
1357 class CoverSheetPage : public StandardPage
1361 CoverSheetPage (wxSize panel_size, int border)
1362 #ifdef DCPOMATIC_OSX
1363 /* We have to force both width and height of this one */
1364 : StandardPage (wxSize (480, 128), border)
1366 : StandardPage (panel_size, border)
1370 wxString GetName () const
1372 return _("Cover Sheet");
1375 #ifdef DCPOMATIC_OSX
1376 wxBitmap GetLargeIcon () const
1378 return wxBitmap ("cover_sheet", wxBITMAP_TYPE_PNG_RESOURCE);
1385 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1386 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1388 _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
1389 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1391 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1392 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1395 void config_changed ()
1397 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
1400 void cover_sheet_changed ()
1402 if (_cover_sheet->GetValue().IsEmpty ()) {
1403 /* Sometimes we get sent an erroneous notification that the cover sheet
1404 is empty; I don't know why.
1408 Config::instance()->set_cover_sheet (wx_to_std (_cover_sheet->GetValue ()));
1411 void reset_cover_sheet ()
1413 Config::instance()->reset_cover_sheet ();
1414 checked_set (_cover_sheet, Config::instance()->cover_sheet ());
1417 wxTextCtrl* _cover_sheet;
1418 wxButton* _reset_cover_sheet;
1422 /** @class AdvancedPage
1423 * @brief Advanced page of the preferences dialog.
1425 class AdvancedPage : public StockPage
1428 AdvancedPage (wxSize panel_size, int border)
1429 : StockPage (Kind_Advanced, panel_size, border)
1430 , _maximum_j2k_bandwidth (0)
1431 , _allow_any_dcp_frame_rate (0)
1432 , _only_servers_encode (0)
1437 , _log_debug_decode (0)
1438 , _log_debug_encode (0)
1439 , _log_debug_email (0)
1443 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1445 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1447 flags |= wxALIGN_RIGHT;
1450 wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
1451 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1456 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1457 table->AddGrowableCol (1, 1);
1458 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1461 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1462 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1463 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1464 s->Add (_maximum_j2k_bandwidth, 1);
1465 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1469 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1470 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1471 table->AddSpacer (0);
1473 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1474 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1475 table->AddSpacer (0);
1478 add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
1479 dcp::NameFormat::Map titles;
1480 titles['t'] = "type (cpl/pkl)";
1481 dcp::NameFormat::Map examples;
1482 examples['t'] = "cpl";
1483 _dcp_metadata_filename_format = new NameFormatEditor (
1484 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1486 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1490 add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
1491 dcp::NameFormat::Map titles;
1492 titles['t'] = "type (j2c/pcm/sub)";
1493 titles['r'] = "reel number";
1494 titles['n'] = "number of reels";
1495 titles['c'] = "content filename";
1496 dcp::NameFormat::Map examples;
1497 examples['t'] = "j2c";
1498 examples['r'] = "1";
1499 examples['n'] = "4";
1500 examples['c'] = "myfile.mp4";
1501 _dcp_asset_filename_format = new NameFormatEditor (
1502 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1504 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1508 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1509 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1510 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1511 t->Add (_log_general, 1, wxEXPAND | wxALL);
1512 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1513 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1514 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1515 t->Add (_log_error, 1, wxEXPAND | wxALL);
1516 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1517 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1518 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1519 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1520 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1521 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1522 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1523 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1524 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1525 table->Add (t, 0, wxALL, 6);
1528 #ifdef DCPOMATIC_WINDOWS
1529 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1530 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1531 table->AddSpacer (0);
1534 _maximum_j2k_bandwidth->SetRange (1, 1000);
1535 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1536 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1537 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1538 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1539 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1540 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1541 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1542 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1543 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1544 _log_debug_decode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1545 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1546 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1547 #ifdef DCPOMATIC_WINDOWS
1548 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1552 void config_changed ()
1554 Config* config = Config::instance ();
1556 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1557 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1558 checked_set (_only_servers_encode, config->only_servers_encode ());
1559 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1560 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1561 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1562 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1563 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1564 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1565 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1566 #ifdef DCPOMATIC_WINDOWS
1567 checked_set (_win32_console, config->win32_console());
1571 void maximum_j2k_bandwidth_changed ()
1573 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1576 void allow_any_dcp_frame_rate_changed ()
1578 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1581 void only_servers_encode_changed ()
1583 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1586 void dcp_metadata_filename_format_changed ()
1588 Config::instance()->set_dcp_metadata_filename_format (_dcp_metadata_filename_format->get ());
1591 void dcp_asset_filename_format_changed ()
1593 Config::instance()->set_dcp_asset_filename_format (_dcp_asset_filename_format->get ());
1599 if (_log_general->GetValue ()) {
1600 types |= LogEntry::TYPE_GENERAL;
1602 if (_log_warning->GetValue ()) {
1603 types |= LogEntry::TYPE_WARNING;
1605 if (_log_error->GetValue ()) {
1606 types |= LogEntry::TYPE_ERROR;
1608 if (_log_timing->GetValue ()) {
1609 types |= LogEntry::TYPE_TIMING;
1611 if (_log_debug_decode->GetValue ()) {
1612 types |= LogEntry::TYPE_DEBUG_DECODE;
1614 if (_log_debug_encode->GetValue ()) {
1615 types |= LogEntry::TYPE_DEBUG_ENCODE;
1617 if (_log_debug_email->GetValue ()) {
1618 types |= LogEntry::TYPE_DEBUG_EMAIL;
1620 Config::instance()->set_log_types (types);
1623 #ifdef DCPOMATIC_WINDOWS
1624 void win32_console_changed ()
1626 Config::instance()->set_win32_console (_win32_console->GetValue ());
1630 wxSpinCtrl* _maximum_j2k_bandwidth;
1631 wxCheckBox* _allow_any_dcp_frame_rate;
1632 wxCheckBox* _only_servers_encode;
1633 NameFormatEditor* _dcp_metadata_filename_format;
1634 NameFormatEditor* _dcp_asset_filename_format;
1635 wxCheckBox* _log_general;
1636 wxCheckBox* _log_warning;
1637 wxCheckBox* _log_error;
1638 wxCheckBox* _log_timing;
1639 wxCheckBox* _log_debug_decode;
1640 wxCheckBox* _log_debug_encode;
1641 wxCheckBox* _log_debug_email;
1642 #ifdef DCPOMATIC_WINDOWS
1643 wxCheckBox* _win32_console;
1647 wxPreferencesEditor*
1648 create_full_config_dialog ()
1650 wxPreferencesEditor* e = new wxPreferencesEditor ();
1652 #ifdef DCPOMATIC_OSX
1653 /* Width that we force some of the config panels to be on OSX so that
1654 the containing window doesn't shrink too much when we select those panels.
1655 This is obviously an unpleasant hack.
1657 wxSize ps = wxSize (520, -1);
1658 int const border = 16;
1660 wxSize ps = wxSize (-1, -1);
1661 int const border = 8;
1664 e->AddPage (new FullGeneralPage (ps, border));
1665 e->AddPage (new DefaultsPage (ps, border));
1666 e->AddPage (new EncodingServersPage (ps, border));
1667 e->AddPage (new KeysPage (ps, border));
1668 e->AddPage (new TMSPage (ps, border));
1669 e->AddPage (new KDMEmailPage (ps, border));
1670 e->AddPage (new CoverSheetPage (ps, border));
1671 e->AddPage (new AdvancedPage (ps, border));