2 Copyright (C) 2012-2014 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 wxWindow* CreateWindow (wxWindow* parent)
93 wxPanel* panel = make_panel (parent);
95 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
96 table->AddGrowableCol (1, 1);
97 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
99 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
100 table->Add (_set_language, 1);
101 _language = new wxChoice (panel, wxID_ANY);
102 _language->Append (wxT ("Deutsch"));
103 _language->Append (wxT ("English"));
104 _language->Append (wxT ("Español"));
105 _language->Append (wxT ("Français"));
106 _language->Append (wxT ("Italiano"));
107 _language->Append (wxT ("Nederlands"));
108 _language->Append (wxT ("Svenska"));
109 table->Add (_language);
111 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
112 wxFont font = restart->GetFont();
113 font.SetStyle (wxFONTSTYLE_ITALIC);
114 font.SetPointSize (font.GetPointSize() - 1);
115 restart->SetFont (font);
116 table->AddSpacer (0);
118 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
119 _num_local_encoding_threads = new wxSpinCtrl (panel);
120 table->Add (_num_local_encoding_threads, 1);
122 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
123 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
124 table->AddSpacer (0);
126 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
127 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
128 table->AddSpacer (0);
130 Config* config = Config::instance ();
132 _set_language->SetValue (config->language ());
134 if (config->language().get_value_or ("") == "fr") {
135 _language->SetSelection (3);
136 } else if (config->language().get_value_or ("") == "it") {
137 _language->SetSelection (4);
138 } else if (config->language().get_value_or ("") == "es") {
139 _language->SetSelection (2);
140 } else if (config->language().get_value_or ("") == "sv") {
141 _language->SetSelection (6);
142 } else if (config->language().get_value_or ("") == "de") {
143 _language->SetSelection (0);
144 } else if (config->language().get_value_or ("") == "nl") {
145 _language->SetSelection (5);
147 _language->SetSelection (1);
150 setup_language_sensitivity ();
152 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
153 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
155 _num_local_encoding_threads->SetRange (1, 128);
156 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
157 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
159 _check_for_updates->SetValue (config->check_for_updates ());
160 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
161 _check_for_test_updates->SetValue (config->check_for_test_updates ());
162 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
168 void setup_language_sensitivity ()
170 _language->Enable (_set_language->GetValue ());
173 void set_language_changed ()
175 setup_language_sensitivity ();
176 if (_set_language->GetValue ()) {
179 Config::instance()->unset_language ();
183 void language_changed ()
185 switch (_language->GetSelection ()) {
187 Config::instance()->set_language ("de");
190 Config::instance()->set_language ("en");
193 Config::instance()->set_language ("es");
196 Config::instance()->set_language ("fr");
199 Config::instance()->set_language ("it");
202 Config::instance()->set_language ("nl");
205 Config::instance()->set_language ("sv");
210 void check_for_updates_changed ()
212 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
215 void check_for_test_updates_changed ()
217 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
220 void num_local_encoding_threads_changed ()
222 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
225 wxCheckBox* _set_language;
227 wxSpinCtrl* _num_local_encoding_threads;
228 wxCheckBox* _check_for_updates;
229 wxCheckBox* _check_for_test_updates;
232 class DefaultsPage : public wxPreferencesPage, public Page
235 DefaultsPage (wxSize panel_size, int border)
236 : Page (panel_size, border)
239 wxString GetName () const
241 return _("Defaults");
245 wxBitmap GetLargeIcon () const
247 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
251 wxWindow* CreateWindow (wxWindow* parent)
253 wxPanel* panel = make_panel (parent);
255 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
256 table->AddGrowableCol (1, 1);
257 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
260 add_label_to_sizer (table, panel, _("Default duration of still images"), true);
261 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
262 _still_length = new wxSpinCtrl (panel);
263 s->Add (_still_length);
264 add_label_to_sizer (s, panel, _("s"), false);
268 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
269 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
270 _directory = new DirPickerCtrl (panel);
272 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
274 table->Add (_directory, 1, wxEXPAND);
276 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
277 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
278 table->Add (_isdcf_metadata_button);
280 add_label_to_sizer (table, panel, _("Default container"), true);
281 _container = new wxChoice (panel, wxID_ANY);
282 table->Add (_container);
284 add_label_to_sizer (table, panel, _("Default content type"), true);
285 _dcp_content_type = new wxChoice (panel, wxID_ANY);
286 table->Add (_dcp_content_type);
289 add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
290 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
291 _j2k_bandwidth = new wxSpinCtrl (panel);
292 s->Add (_j2k_bandwidth);
293 add_label_to_sizer (s, panel, _("Mbit/s"), false);
298 add_label_to_sizer (table, panel, _("Default audio delay"), true);
299 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
300 _audio_delay = new wxSpinCtrl (panel);
301 s->Add (_audio_delay);
302 add_label_to_sizer (s, panel, _("ms"), false);
306 add_label_to_sizer (table, panel, _("Default issuer"), true);
307 _issuer = new wxTextCtrl (panel, wxID_ANY);
308 table->Add (_issuer, 1, wxEXPAND);
310 Config* config = Config::instance ();
312 _still_length->SetRange (1, 3600);
313 _still_length->SetValue (config->default_still_length ());
314 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
316 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
317 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
319 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
321 vector<Ratio const *> ratios = Ratio::all ();
322 for (size_t i = 0; i < ratios.size(); ++i) {
323 _container->Append (std_to_wx (ratios[i]->nickname ()));
324 if (ratios[i] == config->default_container ()) {
325 _container->SetSelection (i);
329 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
331 vector<DCPContentType const *> const ct = DCPContentType::all ();
332 for (size_t i = 0; i < ct.size(); ++i) {
333 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
334 if (ct[i] == config->default_dcp_content_type ()) {
335 _dcp_content_type->SetSelection (i);
339 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
341 _j2k_bandwidth->SetRange (50, 250);
342 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
343 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
345 _audio_delay->SetRange (-1000, 1000);
346 _audio_delay->SetValue (config->default_audio_delay ());
347 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
349 _issuer->SetValue (std_to_wx (config->dcp_issuer ()));
350 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
356 void j2k_bandwidth_changed ()
358 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
361 void audio_delay_changed ()
363 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
366 void directory_changed ()
368 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
371 void edit_isdcf_metadata_clicked (wxWindow* parent)
373 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
375 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
379 void still_length_changed ()
381 Config::instance()->set_default_still_length (_still_length->GetValue ());
384 void container_changed ()
386 vector<Ratio const *> ratio = Ratio::all ();
387 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
390 void dcp_content_type_changed ()
392 vector<DCPContentType const *> ct = DCPContentType::all ();
393 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
396 void issuer_changed ()
398 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
401 wxSpinCtrl* _j2k_bandwidth;
402 wxSpinCtrl* _audio_delay;
403 wxButton* _isdcf_metadata_button;
404 wxSpinCtrl* _still_length;
405 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
406 DirPickerCtrl* _directory;
408 wxDirPickerCtrl* _directory;
410 wxChoice* _container;
411 wxChoice* _dcp_content_type;
415 class EncodingServersPage : public wxPreferencesPage, public Page
418 EncodingServersPage (wxSize panel_size, int border)
419 : Page (panel_size, border)
422 wxString GetName () const
428 wxBitmap GetLargeIcon () const
430 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
434 wxWindow* CreateWindow (wxWindow* parent)
436 wxPanel* panel = make_panel (parent);
438 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
439 panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
441 vector<string> columns;
442 columns.push_back (wx_to_std (_("IP address / host name")));
443 _servers_list = new EditableList<string, ServerDialog> (
446 boost::bind (&Config::servers, Config::instance()),
447 boost::bind (&Config::set_servers, Config::instance(), _1),
448 boost::bind (&EncodingServersPage::server_column, this, _1)
451 panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
453 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
454 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
461 void use_any_servers_changed ()
463 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
466 string server_column (string s)
471 wxCheckBox* _use_any_servers;
472 EditableList<string, ServerDialog>* _servers_list;
475 class ColourConversionsPage : public wxPreferencesPage, public Page
478 ColourConversionsPage (wxSize panel_size, int border)
479 : Page (panel_size, border)
482 wxString GetName () const
484 return _("Colour Conversions");
488 wxBitmap GetLargeIcon () const
490 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
493 wxWindow* CreateWindow (wxWindow* parent)
495 wxPanel* panel = make_panel (parent);
497 vector<string> columns;
498 columns.push_back (wx_to_std (_("Name")));
499 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
502 boost::bind (&Config::colour_conversions, Config::instance()),
503 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
504 boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
508 panel->GetSizer()->Add (list, 1, wxEXPAND | wxALL, _border);
513 string colour_conversion_column (PresetColourConversion c)
519 class KeysPage : public wxPreferencesPage, public Page
522 KeysPage (wxSize panel_size, int border)
523 : Page (panel_size, border)
526 wxString GetName () const
532 wxBitmap GetLargeIcon () const
534 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
538 wxWindow* CreateWindow (wxWindow* parent)
540 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
541 wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
542 _panel->SetSizer (overall_sizer);
544 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Certificate chain for signing DCPs and KDMs:"));
545 overall_sizer->Add (m, 0, wxALL, _border);
547 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
548 overall_sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
550 _certificates = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (400, 200), wxLC_REPORT | wxLC_SINGLE_SEL);
555 ip.SetText (_("Type"));
557 _certificates->InsertColumn (0, ip);
563 ip.SetText (_("Thumbprint"));
566 wxFont font = ip.GetFont ();
567 font.SetFamily (wxFONTFAMILY_TELETYPE);
570 _certificates->InsertColumn (1, ip);
573 certificates_sizer->Add (_certificates, 1, wxEXPAND);
576 wxSizer* s = new wxBoxSizer (wxVERTICAL);
577 _add_certificate = new wxButton (_panel, wxID_ANY, _("Add..."));
578 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
579 _remove_certificate = new wxButton (_panel, wxID_ANY, _("Remove"));
580 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
581 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
584 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
585 table->AddGrowableCol (1, 1);
586 overall_sizer->Add (table, 1, wxALL | wxEXPAND, _border);
588 _remake_certificates = new wxButton (_panel, wxID_ANY, _("Re-make certificates..."));
589 table->Add (_remake_certificates, 0);
590 table->AddSpacer (0);
592 add_label_to_sizer (table, _panel, _("Private key for leaf certificate"), true);
594 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
595 _signer_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
596 wxFont font = _signer_private_key->GetFont ();
597 font.SetFamily (wxFONTFAMILY_TELETYPE);
598 _signer_private_key->SetFont (font);
599 s->Add (_signer_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
600 _load_signer_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
601 s->Add (_load_signer_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
605 add_label_to_sizer (table, _panel, _("Certificate for decrypting DCPs"), true);
607 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
608 _decryption_certificate = new wxStaticText (_panel, wxID_ANY, wxT (""));
609 wxFont font = _decryption_certificate->GetFont ();
610 font.SetFamily (wxFONTFAMILY_TELETYPE);
611 _decryption_certificate->SetFont (font);
612 s->Add (_decryption_certificate, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
613 _load_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Load..."));
614 s->Add (_load_decryption_certificate, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
618 add_label_to_sizer (table, _panel, _("Private key for decrypting DCPs"), true);
620 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
621 _decryption_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
622 wxFont font = _decryption_private_key->GetFont ();
623 font.SetFamily (wxFONTFAMILY_TELETYPE);
624 _decryption_private_key->SetFont (font);
625 s->Add (_decryption_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
626 _load_decryption_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
627 s->Add (_load_decryption_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
631 _export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export DCP decryption certificate..."));
632 table->Add (_export_decryption_certificate);
633 table->AddSpacer (0);
635 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::add_certificate, this));
636 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remove_certificate, this));
637 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KeysPage::update_sensitivity, this));
638 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KeysPage::update_sensitivity, this));
639 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remake_certificates, this));
640 _load_signer_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_signer_private_key, this));
641 _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
642 _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
643 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
645 _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
647 update_certificate_list ();
648 update_signer_private_key ();
649 update_decryption_certificate ();
650 update_decryption_private_key ();
651 update_sensitivity ();
657 void add_certificate ()
659 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
661 if (d->ShowModal() == wxID_OK) {
663 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
664 _signer->certificates().add (c);
665 Config::instance()->set_signer (_signer);
666 update_certificate_list ();
667 } catch (dcp::MiscError& e) {
668 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
674 update_sensitivity ();
677 void remove_certificate ()
679 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
684 _certificates->DeleteItem (i);
685 _signer->certificates().remove (i);
686 Config::instance()->set_signer (_signer);
688 update_sensitivity ();
691 void update_certificate_list ()
693 _certificates->DeleteAllItems ();
694 dcp::CertificateChain::List certs = _signer->certificates().root_to_leaf ();
696 for (dcp::CertificateChain::List::const_iterator i = certs.begin(); i != certs.end(); ++i) {
699 _certificates->InsertItem (item);
700 _certificates->SetItem (n, 1, std_to_wx (i->thumbprint ()));
703 _certificates->SetItem (n, 0, _("Root"));
704 } else if (n == (certs.size() - 1)) {
705 _certificates->SetItem (n, 0, _("Leaf"));
707 _certificates->SetItem (n, 0, _("Intermediate"));
714 void remake_certificates ()
716 MakeSignerChainDialog* d = new MakeSignerChainDialog (_panel);
717 if (d->ShowModal () == wxID_OK) {
722 d->organisational_unit (),
723 d->root_common_name (),
724 d->intermediate_common_name (),
725 d->leaf_common_name ()
729 Config::instance()->set_signer (_signer);
730 update_certificate_list ();
731 update_signer_private_key ();
737 void update_sensitivity ()
739 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
742 void update_signer_private_key ()
744 _signer_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (_signer->key ())));
747 void load_signer_private_key ()
749 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
751 if (d->ShowModal() == wxID_OK) {
753 boost::filesystem::path p (wx_to_std (d->GetPath ()));
754 if (boost::filesystem::file_size (p) > 1024) {
755 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), std_to_wx (p.string ())));
759 _signer->set_key (dcp::file_to_string (p));
760 Config::instance()->set_signer (_signer);
761 update_signer_private_key ();
762 } catch (dcp::MiscError& e) {
763 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
769 update_sensitivity ();
773 void load_decryption_certificate ()
775 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
777 if (d->ShowModal() == wxID_OK) {
779 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
780 Config::instance()->set_decryption_certificate (c);
781 update_decryption_certificate ();
782 } catch (dcp::MiscError& e) {
783 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
790 void update_decryption_certificate ()
792 _decryption_certificate->SetLabel (std_to_wx (Config::instance()->decryption_certificate().thumbprint ()));
795 void load_decryption_private_key ()
797 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
799 if (d->ShowModal() == wxID_OK) {
801 boost::filesystem::path p (wx_to_std (d->GetPath ()));
802 Config::instance()->set_decryption_private_key (dcp::file_to_string (p));
803 update_decryption_private_key ();
804 } catch (dcp::MiscError& e) {
805 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), e.what ()));
812 void update_decryption_private_key ()
814 _decryption_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (Config::instance()->decryption_private_key())));
817 void export_decryption_certificate ()
819 wxFileDialog* d = new wxFileDialog (
820 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
821 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
824 if (d->ShowModal () == wxID_OK) {
825 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
827 throw OpenFileError (wx_to_std (d->GetPath ()));
830 string const s = Config::instance()->decryption_certificate().certificate (true);
831 fwrite (s.c_str(), 1, s.length(), f);
838 wxListCtrl* _certificates;
839 wxButton* _add_certificate;
840 wxButton* _remove_certificate;
841 wxButton* _remake_certificates;
842 wxStaticText* _signer_private_key;
843 wxButton* _load_signer_private_key;
844 wxStaticText* _decryption_certificate;
845 wxButton* _load_decryption_certificate;
846 wxStaticText* _decryption_private_key;
847 wxButton* _load_decryption_private_key;
848 wxButton* _export_decryption_certificate;
849 shared_ptr<dcp::Signer> _signer;
852 class TMSPage : public wxPreferencesPage, public Page
855 TMSPage (wxSize panel_size, int border)
856 : Page (panel_size, border)
859 wxString GetName () const
865 wxBitmap GetLargeIcon () const
867 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
871 wxWindow* CreateWindow (wxWindow* parent)
873 wxPanel* panel = make_panel (parent);
875 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
876 table->AddGrowableCol (1, 1);
877 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
879 add_label_to_sizer (table, panel, _("IP address"), true);
880 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
881 table->Add (_tms_ip, 1, wxEXPAND);
883 add_label_to_sizer (table, panel, _("Target path"), true);
884 _tms_path = new wxTextCtrl (panel, wxID_ANY);
885 table->Add (_tms_path, 1, wxEXPAND);
887 add_label_to_sizer (table, panel, _("User name"), true);
888 _tms_user = new wxTextCtrl (panel, wxID_ANY);
889 table->Add (_tms_user, 1, wxEXPAND);
891 add_label_to_sizer (table, panel, _("Password"), true);
892 _tms_password = new wxTextCtrl (panel, wxID_ANY);
893 table->Add (_tms_password, 1, wxEXPAND);
895 Config* config = Config::instance ();
897 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
898 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
899 _tms_path->SetValue (std_to_wx (config->tms_path ()));
900 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
901 _tms_user->SetValue (std_to_wx (config->tms_user ()));
902 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
903 _tms_password->SetValue (std_to_wx (config->tms_password ()));
904 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
910 void tms_ip_changed ()
912 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
915 void tms_path_changed ()
917 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
920 void tms_user_changed ()
922 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
925 void tms_password_changed ()
927 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
931 wxTextCtrl* _tms_path;
932 wxTextCtrl* _tms_user;
933 wxTextCtrl* _tms_password;
936 class KDMEmailPage : public wxPreferencesPage, public Page
940 KDMEmailPage (wxSize panel_size, int border)
941 : Page (panel_size, border)
944 wxString GetName () const
946 return _("KDM Email");
950 wxBitmap GetLargeIcon () const
952 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
956 wxWindow* CreateWindow (wxWindow* parent)
959 /* We have to force both width and height of this one */
960 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
962 wxPanel* panel = new wxPanel (parent);
964 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
967 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
968 table->AddGrowableCol (1, 1);
969 panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
971 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
972 _mail_server = new wxTextCtrl (panel, wxID_ANY);
973 table->Add (_mail_server, 1, wxEXPAND | wxALL);
975 add_label_to_sizer (table, panel, _("Mail user name"), true);
976 _mail_user = new wxTextCtrl (panel, wxID_ANY);
977 table->Add (_mail_user, 1, wxEXPAND | wxALL);
979 add_label_to_sizer (table, panel, _("Mail password"), true);
980 _mail_password = new wxTextCtrl (panel, wxID_ANY);
981 table->Add (_mail_password, 1, wxEXPAND | wxALL);
983 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
984 wxFont font = plain->GetFont();
985 font.SetStyle (wxFONTSTYLE_ITALIC);
986 font.SetPointSize (font.GetPointSize() - 1);
987 plain->SetFont (font);
988 table->AddSpacer (0);
990 add_label_to_sizer (table, panel, _("Subject"), true);
991 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
992 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
994 add_label_to_sizer (table, panel, _("From address"), true);
995 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
996 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
998 add_label_to_sizer (table, panel, _("CC address"), true);
999 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
1000 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1002 add_label_to_sizer (table, panel, _("BCC address"), true);
1003 _kdm_bcc = new wxTextCtrl (panel, wxID_ANY);
1004 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1006 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
1007 panel->GetSizer()->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
1009 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
1010 panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1012 Config* config = Config::instance ();
1013 _mail_server->SetValue (std_to_wx (config->mail_server ()));
1014 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1015 _mail_user->SetValue (std_to_wx (config->mail_user ()));
1016 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1017 _mail_password->SetValue (std_to_wx (config->mail_password ()));
1018 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1019 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
1020 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1021 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
1022 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1023 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
1024 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
1025 _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
1026 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1027 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1028 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
1029 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1035 void mail_server_changed ()
1037 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1040 void mail_user_changed ()
1042 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1045 void mail_password_changed ()
1047 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1050 void kdm_subject_changed ()
1052 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1055 void kdm_from_changed ()
1057 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1060 void kdm_cc_changed ()
1062 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
1065 void kdm_bcc_changed ()
1067 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1070 void kdm_email_changed ()
1072 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1075 void reset_kdm_email ()
1077 Config::instance()->reset_kdm_email ();
1078 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
1081 wxTextCtrl* _mail_server;
1082 wxTextCtrl* _mail_user;
1083 wxTextCtrl* _mail_password;
1084 wxTextCtrl* _kdm_subject;
1085 wxTextCtrl* _kdm_from;
1086 wxTextCtrl* _kdm_cc;
1087 wxTextCtrl* _kdm_bcc;
1088 wxTextCtrl* _kdm_email;
1089 wxButton* _reset_kdm_email;
1092 /** @class AdvancedPage
1093 * @brief Advanced page of the preferences dialog.
1095 class AdvancedPage : public wxStockPreferencesPage, public Page
1099 AdvancedPage (wxSize panel_size, int border)
1100 : wxStockPreferencesPage (Kind_Advanced)
1101 , Page (panel_size, border)
1104 wxWindow* CreateWindow (wxWindow* parent)
1106 wxPanel* panel = make_panel (parent);
1108 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1109 table->AddGrowableCol (1, 1);
1110 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1113 add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
1114 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1115 _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
1116 s->Add (_maximum_j2k_bandwidth, 1);
1117 add_label_to_sizer (s, panel, _("Mbit/s"), false);
1121 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
1122 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1123 table->AddSpacer (0);
1126 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log:"));
1127 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1129 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log"));
1130 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1134 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1135 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
1136 t->Add (_log_general, 1, wxEXPAND | wxALL);
1137 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
1138 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1139 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
1140 t->Add (_log_error, 1, wxEXPAND | wxALL);
1141 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
1142 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1143 table->Add (t, 0, wxALL, 6);
1146 #ifdef DCPOMATIC_WINDOWS
1147 _win32_console = new wxCheckBox (panel, wxID_ANY, _("Open console window"));
1148 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1149 table->AddSpacer (0);
1152 Config* config = Config::instance ();
1154 _maximum_j2k_bandwidth->SetRange (1, 500);
1155 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
1156 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1157 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
1158 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1159 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
1160 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1161 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
1162 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1163 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
1164 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1165 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
1166 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1167 #ifdef DCPOMATIC_WINDOWS
1168 _win32_console->SetValue (config->win32_console());
1169 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1177 void maximum_j2k_bandwidth_changed ()
1179 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1182 void allow_any_dcp_frame_rate_changed ()
1184 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1190 if (_log_general->GetValue ()) {
1191 types |= Log::TYPE_GENERAL;
1193 if (_log_warning->GetValue ()) {
1194 types |= Log::TYPE_WARNING;
1196 if (_log_error->GetValue ()) {
1197 types |= Log::TYPE_ERROR;
1199 if (_log_timing->GetValue ()) {
1200 types |= Log::TYPE_TIMING;
1202 Config::instance()->set_log_types (types);
1205 #ifdef DCPOMATIC_WINDOWS
1206 void win32_console_changed ()
1208 Config::instance()->set_win32_console (_win32_console->GetValue ());
1212 wxSpinCtrl* _maximum_j2k_bandwidth;
1213 wxCheckBox* _allow_any_dcp_frame_rate;
1214 wxCheckBox* _log_general;
1215 wxCheckBox* _log_warning;
1216 wxCheckBox* _log_error;
1217 wxCheckBox* _log_timing;
1218 #ifdef DCPOMATIC_WINDOWS
1219 wxCheckBox* _win32_console;
1223 wxPreferencesEditor*
1224 create_config_dialog ()
1226 wxPreferencesEditor* e = new wxPreferencesEditor ();
1228 #ifdef DCPOMATIC_OSX
1229 /* Width that we force some of the config panels to be on OSX so that
1230 the containing window doesn't shrink too much when we select those panels.
1231 This is obviously an unpleasant hack.
1233 wxSize ps = wxSize (520, -1);
1234 int const border = 16;
1236 wxSize ps = wxSize (-1, -1);
1237 int const border = 8;
1240 e->AddPage (new GeneralPage (ps, border));
1241 e->AddPage (new DefaultsPage (ps, border));
1242 e->AddPage (new EncodingServersPage (ps, border));
1243 e->AddPage (new ColourConversionsPage (ps, border));
1244 e->AddPage (new KeysPage (ps, border));
1245 e->AddPage (new TMSPage (ps, border));
1246 e->AddPage (new KDMEmailPage (ps, border));
1247 e->AddPage (new AdvancedPage (ps, border));