2 Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /** @file src/config_dialog.cc
21 * @brief A dialogue to edit DCP-o-matic configuration.
25 #include <boost/lexical_cast.hpp>
26 #include <boost/filesystem.hpp>
27 #include <wx/stdpaths.h>
28 #include <wx/preferences.h>
29 #include <wx/filepicker.h>
30 #include <wx/spinctrl.h>
31 #include <dcp/colour_matrix.h>
32 #include <dcp/exceptions.h>
33 #include <dcp/signer.h>
34 #include "lib/config.h"
35 #include "lib/ratio.h"
36 #include "lib/scaler.h"
37 #include "lib/filter.h"
38 #include "lib/dcp_content_type.h"
39 #include "lib/colour_conversion.h"
42 #include "lib/cross.h"
43 #include "lib/exceptions.h"
44 #include "config_dialog.h"
46 #include "editable_list.h"
47 #include "filter_dialog.h"
48 #include "dir_picker_ctrl.h"
49 #include "isdcf_metadata_dialog.h"
50 #include "preset_colour_conversion_dialog.h"
51 #include "server_dialog.h"
52 #include "make_signer_chain_dialog.h"
59 using boost::shared_ptr;
60 using boost::lexical_cast;
65 Page (wxSize panel_size, int border)
66 : _panel_size (panel_size)
71 wxPanel* make_panel (wxWindow* parent)
73 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
74 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
83 class GeneralPage : public wxStockPreferencesPage, public Page
86 GeneralPage (wxSize panel_size, int border)
87 : wxStockPreferencesPage (Kind_General)
88 , Page (panel_size, border)
91 , _num_local_encoding_threads (0)
92 , _check_for_updates (0)
93 , _check_for_test_updates (0)
96 wxWindow* CreateWindow (wxWindow* parent)
98 wxPanel* panel = make_panel (parent);
100 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
101 table->AddGrowableCol (1, 1);
102 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
104 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
105 table->Add (_set_language, 1);
106 _language = new wxChoice (panel, wxID_ANY);
107 _language->Append (wxT ("Deutsch"));
108 _language->Append (wxT ("English"));
109 _language->Append (wxT ("Español"));
110 _language->Append (wxT ("Français"));
111 _language->Append (wxT ("Italiano"));
112 _language->Append (wxT ("Nederlands"));
113 _language->Append (wxT ("Svenska"));
114 table->Add (_language);
116 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
117 wxFont font = restart->GetFont();
118 font.SetStyle (wxFONTSTYLE_ITALIC);
119 font.SetPointSize (font.GetPointSize() - 1);
120 restart->SetFont (font);
121 table->AddSpacer (0);
123 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
124 _num_local_encoding_threads = new wxSpinCtrl (panel);
125 table->Add (_num_local_encoding_threads, 1);
127 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
128 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
129 table->AddSpacer (0);
131 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
132 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
133 table->AddSpacer (0);
135 Config* config = Config::instance ();
137 _set_language->SetValue (config->language ());
139 if (config->language().get_value_or ("") == "fr") {
140 _language->SetSelection (3);
141 } else if (config->language().get_value_or ("") == "it") {
142 _language->SetSelection (4);
143 } else if (config->language().get_value_or ("") == "es") {
144 _language->SetSelection (2);
145 } else if (config->language().get_value_or ("") == "sv") {
146 _language->SetSelection (6);
147 } else if (config->language().get_value_or ("") == "de") {
148 _language->SetSelection (0);
149 } else if (config->language().get_value_or ("") == "nl") {
150 _language->SetSelection (5);
152 _language->SetSelection (1);
155 setup_language_sensitivity ();
157 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
158 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
160 _num_local_encoding_threads->SetRange (1, 128);
161 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
162 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
164 _check_for_updates->SetValue (config->check_for_updates ());
165 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
166 _check_for_test_updates->SetValue (config->check_for_test_updates ());
167 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
173 void setup_language_sensitivity ()
175 _language->Enable (_set_language->GetValue ());
178 void set_language_changed ()
180 setup_language_sensitivity ();
181 if (_set_language->GetValue ()) {
184 Config::instance()->unset_language ();
188 void language_changed ()
190 switch (_language->GetSelection ()) {
192 Config::instance()->set_language ("de");
195 Config::instance()->set_language ("en");
198 Config::instance()->set_language ("es");
201 Config::instance()->set_language ("fr");
204 Config::instance()->set_language ("it");
207 Config::instance()->set_language ("nl");
210 Config::instance()->set_language ("sv");
215 void check_for_updates_changed ()
217 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
220 void check_for_test_updates_changed ()
222 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
225 void num_local_encoding_threads_changed ()
227 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
230 wxCheckBox* _set_language;
232 wxSpinCtrl* _num_local_encoding_threads;
233 wxCheckBox* _check_for_updates;
234 wxCheckBox* _check_for_test_updates;
237 class DefaultsPage : public wxPreferencesPage, public Page
240 DefaultsPage (wxSize panel_size, int border)
241 : Page (panel_size, border)
244 , _isdcf_metadata_button (0)
248 , _dcp_content_type (0)
252 wxString GetName () const
254 return _("Defaults");
258 wxBitmap GetLargeIcon () const
260 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
264 wxWindow* CreateWindow (wxWindow* parent)
266 wxPanel* panel = make_panel (parent);
268 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
269 table->AddGrowableCol (1, 1);
270 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
273 add_label_to_sizer (table, panel, _("Default duration of still images"), true);
274 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
275 _still_length = new wxSpinCtrl (panel);
276 s->Add (_still_length);
277 add_label_to_sizer (s, panel, _("s"), false);
281 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
282 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
283 _directory = new DirPickerCtrl (panel);
285 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
287 table->Add (_directory, 1, wxEXPAND);
289 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
290 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
291 table->Add (_isdcf_metadata_button);
293 add_label_to_sizer (table, panel, _("Default container"), true);
294 _container = new wxChoice (panel, wxID_ANY);
295 table->Add (_container);
297 add_label_to_sizer (table, panel, _("Default content type"), true);
298 _dcp_content_type = new wxChoice (panel, wxID_ANY);
299 table->Add (_dcp_content_type);
302 add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
303 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
304 _j2k_bandwidth = new wxSpinCtrl (panel);
305 s->Add (_j2k_bandwidth);
306 add_label_to_sizer (s, panel, _("Mbit/s"), false);
311 add_label_to_sizer (table, panel, _("Default audio delay"), true);
312 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
313 _audio_delay = new wxSpinCtrl (panel);
314 s->Add (_audio_delay);
315 add_label_to_sizer (s, panel, _("ms"), false);
319 add_label_to_sizer (table, panel, _("Default issuer"), true);
320 _issuer = new wxTextCtrl (panel, wxID_ANY);
321 table->Add (_issuer, 1, wxEXPAND);
323 Config* config = Config::instance ();
325 _still_length->SetRange (1, 3600);
326 _still_length->SetValue (config->default_still_length ());
327 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
329 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
330 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
332 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
334 vector<Ratio const *> ratios = Ratio::all ();
335 for (size_t i = 0; i < ratios.size(); ++i) {
336 _container->Append (std_to_wx (ratios[i]->nickname ()));
337 if (ratios[i] == config->default_container ()) {
338 _container->SetSelection (i);
342 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
344 vector<DCPContentType const *> const ct = DCPContentType::all ();
345 for (size_t i = 0; i < ct.size(); ++i) {
346 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
347 if (ct[i] == config->default_dcp_content_type ()) {
348 _dcp_content_type->SetSelection (i);
352 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
354 _j2k_bandwidth->SetRange (50, 250);
355 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
356 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
358 _audio_delay->SetRange (-1000, 1000);
359 _audio_delay->SetValue (config->default_audio_delay ());
360 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
362 _issuer->SetValue (std_to_wx (config->dcp_issuer ()));
363 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
365 _config_connection = config->Changed.connect (boost::bind (&DefaultsPage::config_changed, this));
371 void config_changed ()
373 _j2k_bandwidth->SetRange (50, Config::instance()->maximum_j2k_bandwidth() / 1000000);
376 void j2k_bandwidth_changed ()
378 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
381 void audio_delay_changed ()
383 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
386 void directory_changed ()
388 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
391 void edit_isdcf_metadata_clicked (wxWindow* parent)
393 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
395 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
399 void still_length_changed ()
401 Config::instance()->set_default_still_length (_still_length->GetValue ());
404 void container_changed ()
406 vector<Ratio const *> ratio = Ratio::all ();
407 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
410 void dcp_content_type_changed ()
412 vector<DCPContentType const *> ct = DCPContentType::all ();
413 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
416 void issuer_changed ()
418 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
421 wxSpinCtrl* _j2k_bandwidth;
422 wxSpinCtrl* _audio_delay;
423 wxButton* _isdcf_metadata_button;
424 wxSpinCtrl* _still_length;
425 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
426 DirPickerCtrl* _directory;
428 wxDirPickerCtrl* _directory;
430 wxChoice* _container;
431 wxChoice* _dcp_content_type;
434 boost::signals2::scoped_connection _config_connection;
437 class EncodingServersPage : public wxPreferencesPage, public Page
440 EncodingServersPage (wxSize panel_size, int border)
441 : Page (panel_size, border)
442 , _use_any_servers (0)
446 wxString GetName () const
452 wxBitmap GetLargeIcon () const
454 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
458 wxWindow* CreateWindow (wxWindow* parent)
460 wxPanel* panel = make_panel (parent);
462 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
463 panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
465 vector<string> columns;
466 columns.push_back (wx_to_std (_("IP address / host name")));
467 _servers_list = new EditableList<string, ServerDialog> (
470 boost::bind (&Config::servers, Config::instance()),
471 boost::bind (&Config::set_servers, Config::instance(), _1),
472 boost::bind (&EncodingServersPage::server_column, this, _1)
475 panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
477 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
478 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
485 void use_any_servers_changed ()
487 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
490 string server_column (string s)
495 wxCheckBox* _use_any_servers;
496 EditableList<string, ServerDialog>* _servers_list;
499 class ColourConversionsPage : public wxPreferencesPage, public Page
502 ColourConversionsPage (wxSize panel_size, int border)
503 : Page (panel_size, border)
506 wxString GetName () const
508 return _("Colour Conversions");
512 wxBitmap GetLargeIcon () const
514 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
517 wxWindow* CreateWindow (wxWindow* parent)
519 wxPanel* panel = make_panel (parent);
521 vector<string> columns;
522 columns.push_back (wx_to_std (_("Name")));
523 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
526 boost::bind (&Config::colour_conversions, Config::instance()),
527 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
528 boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
532 panel->GetSizer()->Add (list, 1, wxEXPAND | wxALL, _border);
537 string colour_conversion_column (PresetColourConversion c)
543 class KeysPage : public wxPreferencesPage, public Page
546 KeysPage (wxSize panel_size, int border)
547 : Page (panel_size, border)
550 , _add_certificate (0)
551 , _remove_certificate (0)
552 , _remake_certificates (0)
553 , _signer_private_key (0)
554 , _load_signer_private_key (0)
555 , _decryption_certificate (0)
556 , _load_decryption_certificate (0)
557 , _decryption_private_key (0)
558 , _load_decryption_private_key (0)
559 , _export_decryption_certificate (0)
562 wxString GetName () const
568 wxBitmap GetLargeIcon () const
570 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
574 wxWindow* CreateWindow (wxWindow* parent)
576 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
577 wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
578 _panel->SetSizer (overall_sizer);
580 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Certificate chain for signing DCPs and KDMs:"));
581 overall_sizer->Add (m, 0, wxALL, _border);
583 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
584 overall_sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
586 _certificates = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (400, 200), wxLC_REPORT | wxLC_SINGLE_SEL);
591 ip.SetText (_("Type"));
593 _certificates->InsertColumn (0, ip);
599 ip.SetText (_("Thumbprint"));
602 wxFont font = ip.GetFont ();
603 font.SetFamily (wxFONTFAMILY_TELETYPE);
606 _certificates->InsertColumn (1, ip);
609 certificates_sizer->Add (_certificates, 1, wxEXPAND);
612 wxSizer* s = new wxBoxSizer (wxVERTICAL);
613 _add_certificate = new wxButton (_panel, wxID_ANY, _("Add..."));
614 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
615 _remove_certificate = new wxButton (_panel, wxID_ANY, _("Remove"));
616 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
617 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
620 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
621 table->AddGrowableCol (1, 1);
622 overall_sizer->Add (table, 1, wxALL | wxEXPAND, _border);
624 _remake_certificates = new wxButton (_panel, wxID_ANY, _("Re-make certificates..."));
625 table->Add (_remake_certificates, 0);
626 table->AddSpacer (0);
628 add_label_to_sizer (table, _panel, _("Private key for leaf certificate"), true);
630 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
631 _signer_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
632 wxFont font = _signer_private_key->GetFont ();
633 font.SetFamily (wxFONTFAMILY_TELETYPE);
634 _signer_private_key->SetFont (font);
635 s->Add (_signer_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
636 _load_signer_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
637 s->Add (_load_signer_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
641 add_label_to_sizer (table, _panel, _("Certificate for decrypting DCPs"), true);
643 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
644 _decryption_certificate = new wxStaticText (_panel, wxID_ANY, wxT (""));
645 wxFont font = _decryption_certificate->GetFont ();
646 font.SetFamily (wxFONTFAMILY_TELETYPE);
647 _decryption_certificate->SetFont (font);
648 s->Add (_decryption_certificate, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
649 _load_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Load..."));
650 s->Add (_load_decryption_certificate, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
654 add_label_to_sizer (table, _panel, _("Private key for decrypting DCPs"), true);
656 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
657 _decryption_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
658 wxFont font = _decryption_private_key->GetFont ();
659 font.SetFamily (wxFONTFAMILY_TELETYPE);
660 _decryption_private_key->SetFont (font);
661 s->Add (_decryption_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
662 _load_decryption_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
663 s->Add (_load_decryption_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
667 _export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export DCP decryption certificate..."));
668 table->Add (_export_decryption_certificate);
669 table->AddSpacer (0);
671 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::add_certificate, this));
672 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remove_certificate, this));
673 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KeysPage::update_sensitivity, this));
674 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KeysPage::update_sensitivity, this));
675 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remake_certificates, this));
676 _load_signer_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_signer_private_key, this));
677 _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
678 _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
679 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
681 _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
683 update_certificate_list ();
684 update_signer_private_key ();
685 update_decryption_certificate ();
686 update_decryption_private_key ();
687 update_sensitivity ();
693 void add_certificate ()
695 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
697 if (d->ShowModal() == wxID_OK) {
699 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
700 _signer->certificates().add (c);
701 Config::instance()->set_signer (_signer);
702 update_certificate_list ();
703 } catch (dcp::MiscError& e) {
704 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
710 update_sensitivity ();
713 void remove_certificate ()
715 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
720 _certificates->DeleteItem (i);
721 _signer->certificates().remove (i);
722 Config::instance()->set_signer (_signer);
724 update_sensitivity ();
727 void update_certificate_list ()
729 _certificates->DeleteAllItems ();
730 dcp::CertificateChain::List certs = _signer->certificates().root_to_leaf ();
732 for (dcp::CertificateChain::List::const_iterator i = certs.begin(); i != certs.end(); ++i) {
735 _certificates->InsertItem (item);
736 _certificates->SetItem (n, 1, std_to_wx (i->thumbprint ()));
739 _certificates->SetItem (n, 0, _("Root"));
740 } else if (n == (certs.size() - 1)) {
741 _certificates->SetItem (n, 0, _("Leaf"));
743 _certificates->SetItem (n, 0, _("Intermediate"));
750 void remake_certificates ()
752 MakeSignerChainDialog* d = new MakeSignerChainDialog (_panel);
753 if (d->ShowModal () == wxID_OK) {
758 d->organisational_unit (),
759 d->root_common_name (),
760 d->intermediate_common_name (),
761 d->leaf_common_name ()
765 Config::instance()->set_signer (_signer);
766 update_certificate_list ();
767 update_signer_private_key ();
773 void update_sensitivity ()
775 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
778 void update_signer_private_key ()
780 _signer_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (_signer->key ())));
783 void load_signer_private_key ()
785 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
787 if (d->ShowModal() == wxID_OK) {
789 boost::filesystem::path p (wx_to_std (d->GetPath ()));
790 if (boost::filesystem::file_size (p) > 1024) {
791 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), std_to_wx (p.string ())));
795 _signer->set_key (dcp::file_to_string (p));
796 Config::instance()->set_signer (_signer);
797 update_signer_private_key ();
798 } catch (dcp::MiscError& e) {
799 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
805 update_sensitivity ();
809 void load_decryption_certificate ()
811 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
813 if (d->ShowModal() == wxID_OK) {
815 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
816 Config::instance()->set_decryption_certificate (c);
817 update_decryption_certificate ();
818 } catch (dcp::MiscError& e) {
819 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
826 void update_decryption_certificate ()
828 _decryption_certificate->SetLabel (std_to_wx (Config::instance()->decryption_certificate().thumbprint ()));
831 void load_decryption_private_key ()
833 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
835 if (d->ShowModal() == wxID_OK) {
837 boost::filesystem::path p (wx_to_std (d->GetPath ()));
838 Config::instance()->set_decryption_private_key (dcp::file_to_string (p));
839 update_decryption_private_key ();
840 } catch (dcp::MiscError& e) {
841 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), e.what ()));
848 void update_decryption_private_key ()
850 _decryption_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (Config::instance()->decryption_private_key())));
853 void export_decryption_certificate ()
855 wxFileDialog* d = new wxFileDialog (
856 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
857 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
860 if (d->ShowModal () == wxID_OK) {
861 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
863 throw OpenFileError (wx_to_std (d->GetPath ()));
866 string const s = Config::instance()->decryption_certificate().certificate (true);
867 fwrite (s.c_str(), 1, s.length(), f);
874 wxListCtrl* _certificates;
875 wxButton* _add_certificate;
876 wxButton* _remove_certificate;
877 wxButton* _remake_certificates;
878 wxStaticText* _signer_private_key;
879 wxButton* _load_signer_private_key;
880 wxStaticText* _decryption_certificate;
881 wxButton* _load_decryption_certificate;
882 wxStaticText* _decryption_private_key;
883 wxButton* _load_decryption_private_key;
884 wxButton* _export_decryption_certificate;
885 shared_ptr<dcp::Signer> _signer;
888 class TMSPage : public wxPreferencesPage, public Page
891 TMSPage (wxSize panel_size, int border)
892 : Page (panel_size, border)
899 wxString GetName () const
905 wxBitmap GetLargeIcon () const
907 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
911 wxWindow* CreateWindow (wxWindow* parent)
913 wxPanel* panel = make_panel (parent);
915 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
916 table->AddGrowableCol (1, 1);
917 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
919 add_label_to_sizer (table, panel, _("IP address"), true);
920 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
921 table->Add (_tms_ip, 1, wxEXPAND);
923 add_label_to_sizer (table, panel, _("Target path"), true);
924 _tms_path = new wxTextCtrl (panel, wxID_ANY);
925 table->Add (_tms_path, 1, wxEXPAND);
927 add_label_to_sizer (table, panel, _("User name"), true);
928 _tms_user = new wxTextCtrl (panel, wxID_ANY);
929 table->Add (_tms_user, 1, wxEXPAND);
931 add_label_to_sizer (table, panel, _("Password"), true);
932 _tms_password = new wxTextCtrl (panel, wxID_ANY);
933 table->Add (_tms_password, 1, wxEXPAND);
935 Config* config = Config::instance ();
937 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
938 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
939 _tms_path->SetValue (std_to_wx (config->tms_path ()));
940 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
941 _tms_user->SetValue (std_to_wx (config->tms_user ()));
942 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
943 _tms_password->SetValue (std_to_wx (config->tms_password ()));
944 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
950 void tms_ip_changed ()
952 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
955 void tms_path_changed ()
957 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
960 void tms_user_changed ()
962 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
965 void tms_password_changed ()
967 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
971 wxTextCtrl* _tms_path;
972 wxTextCtrl* _tms_user;
973 wxTextCtrl* _tms_password;
976 class KDMEmailPage : public wxPreferencesPage, public Page
980 KDMEmailPage (wxSize panel_size, int border)
981 : Page (panel_size, border)
990 , _reset_kdm_email (0)
993 wxString GetName () const
995 return _("KDM Email");
999 wxBitmap GetLargeIcon () const
1001 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1005 wxWindow* CreateWindow (wxWindow* parent)
1007 #ifdef DCPOMATIC_OSX
1008 /* We have to force both width and height of this one */
1009 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
1011 wxPanel* panel = new wxPanel (parent);
1013 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
1014 panel->SetSizer (s);
1016 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1017 table->AddGrowableCol (1, 1);
1018 panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1020 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
1021 _mail_server = new wxTextCtrl (panel, wxID_ANY);
1022 table->Add (_mail_server, 1, wxEXPAND | wxALL);
1024 add_label_to_sizer (table, panel, _("Mail user name"), true);
1025 _mail_user = new wxTextCtrl (panel, wxID_ANY);
1026 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1028 add_label_to_sizer (table, panel, _("Mail password"), true);
1029 _mail_password = new wxTextCtrl (panel, wxID_ANY);
1030 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1032 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
1033 wxFont font = plain->GetFont();
1034 font.SetStyle (wxFONTSTYLE_ITALIC);
1035 font.SetPointSize (font.GetPointSize() - 1);
1036 plain->SetFont (font);
1037 table->AddSpacer (0);
1039 add_label_to_sizer (table, panel, _("Subject"), true);
1040 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
1041 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1043 add_label_to_sizer (table, panel, _("From address"), true);
1044 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
1045 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1047 add_label_to_sizer (table, panel, _("CC address"), true);
1048 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
1049 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1051 add_label_to_sizer (table, panel, _("BCC address"), true);
1052 _kdm_bcc = new wxTextCtrl (panel, wxID_ANY);
1053 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1055 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
1056 panel->GetSizer()->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
1058 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
1059 panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1061 Config* config = Config::instance ();
1062 _mail_server->SetValue (std_to_wx (config->mail_server ()));
1063 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1064 _mail_user->SetValue (std_to_wx (config->mail_user ()));
1065 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1066 _mail_password->SetValue (std_to_wx (config->mail_password ()));
1067 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1068 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
1069 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1070 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
1071 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1072 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
1073 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
1074 _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
1075 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1076 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1077 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
1078 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1084 void mail_server_changed ()
1086 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1089 void mail_user_changed ()
1091 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1094 void mail_password_changed ()
1096 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1099 void kdm_subject_changed ()
1101 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1104 void kdm_from_changed ()
1106 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1109 void kdm_cc_changed ()
1111 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
1114 void kdm_bcc_changed ()
1116 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1119 void kdm_email_changed ()
1121 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1124 void reset_kdm_email ()
1126 Config::instance()->reset_kdm_email ();
1127 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
1130 wxTextCtrl* _mail_server;
1131 wxTextCtrl* _mail_user;
1132 wxTextCtrl* _mail_password;
1133 wxTextCtrl* _kdm_subject;
1134 wxTextCtrl* _kdm_from;
1135 wxTextCtrl* _kdm_cc;
1136 wxTextCtrl* _kdm_bcc;
1137 wxTextCtrl* _kdm_email;
1138 wxButton* _reset_kdm_email;
1141 /** @class AdvancedPage
1142 * @brief Advanced page of the preferences dialog.
1144 class AdvancedPage : public wxStockPreferencesPage, public Page
1148 AdvancedPage (wxSize panel_size, int border)
1149 : wxStockPreferencesPage (Kind_Advanced)
1150 , Page (panel_size, border)
1151 , _maximum_j2k_bandwidth (0)
1152 , _allow_any_dcp_frame_rate (0)
1159 wxWindow* CreateWindow (wxWindow* parent)
1161 wxPanel* panel = make_panel (parent);
1163 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1164 table->AddGrowableCol (1, 1);
1165 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1168 add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
1169 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1170 _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
1171 s->Add (_maximum_j2k_bandwidth, 1);
1172 add_label_to_sizer (s, panel, _("Mbit/s"), false);
1176 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
1177 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1178 table->AddSpacer (0);
1181 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log:"));
1182 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1184 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log"));
1185 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1189 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1190 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
1191 t->Add (_log_general, 1, wxEXPAND | wxALL);
1192 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
1193 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1194 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
1195 t->Add (_log_error, 1, wxEXPAND | wxALL);
1196 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
1197 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1198 table->Add (t, 0, wxALL, 6);
1201 #ifdef DCPOMATIC_WINDOWS
1202 _win32_console = new wxCheckBox (panel, wxID_ANY, _("Open console window"));
1203 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1204 table->AddSpacer (0);
1207 Config* config = Config::instance ();
1209 _maximum_j2k_bandwidth->SetRange (1, 1000);
1210 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
1211 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1212 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
1213 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1214 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
1215 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1216 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
1217 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1218 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
1219 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1220 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
1221 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1222 #ifdef DCPOMATIC_WINDOWS
1223 _win32_console->SetValue (config->win32_console());
1224 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1232 void maximum_j2k_bandwidth_changed ()
1234 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1237 void allow_any_dcp_frame_rate_changed ()
1239 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1245 if (_log_general->GetValue ()) {
1246 types |= Log::TYPE_GENERAL;
1248 if (_log_warning->GetValue ()) {
1249 types |= Log::TYPE_WARNING;
1251 if (_log_error->GetValue ()) {
1252 types |= Log::TYPE_ERROR;
1254 if (_log_timing->GetValue ()) {
1255 types |= Log::TYPE_TIMING;
1257 Config::instance()->set_log_types (types);
1260 #ifdef DCPOMATIC_WINDOWS
1261 void win32_console_changed ()
1263 Config::instance()->set_win32_console (_win32_console->GetValue ());
1267 wxSpinCtrl* _maximum_j2k_bandwidth;
1268 wxCheckBox* _allow_any_dcp_frame_rate;
1269 wxCheckBox* _log_general;
1270 wxCheckBox* _log_warning;
1271 wxCheckBox* _log_error;
1272 wxCheckBox* _log_timing;
1273 #ifdef DCPOMATIC_WINDOWS
1274 wxCheckBox* _win32_console;
1278 wxPreferencesEditor*
1279 create_config_dialog ()
1281 wxPreferencesEditor* e = new wxPreferencesEditor ();
1283 #ifdef DCPOMATIC_OSX
1284 /* Width that we force some of the config panels to be on OSX so that
1285 the containing window doesn't shrink too much when we select those panels.
1286 This is obviously an unpleasant hack.
1288 wxSize ps = wxSize (520, -1);
1289 int const border = 16;
1291 wxSize ps = wxSize (-1, -1);
1292 int const border = 8;
1295 e->AddPage (new GeneralPage (ps, border));
1296 e->AddPage (new DefaultsPage (ps, border));
1297 e->AddPage (new EncodingServersPage (ps, border));
1298 e->AddPage (new ColourConversionsPage (ps, border));
1299 e->AddPage (new KeysPage (ps, border));
1300 e->AddPage (new TMSPage (ps, border));
1301 e->AddPage (new KDMEmailPage (ps, border));
1302 e->AddPage (new AdvancedPage (ps, border));