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/filter.h"
37 #include "lib/dcp_content_type.h"
38 #include "lib/colour_conversion.h"
41 #include "lib/cross.h"
42 #include "lib/exceptions.h"
43 #include "config_dialog.h"
45 #include "editable_list.h"
46 #include "filter_dialog.h"
47 #include "dir_picker_ctrl.h"
48 #include "isdcf_metadata_dialog.h"
49 #include "preset_colour_conversion_dialog.h"
50 #include "server_dialog.h"
51 #include "make_signer_chain_dialog.h"
58 using boost::shared_ptr;
59 using boost::lexical_cast;
64 Page (wxSize panel_size, int border)
65 : _panel_size (panel_size)
70 wxPanel* make_panel (wxWindow* parent)
72 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
73 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
82 class GeneralPage : public wxStockPreferencesPage, public Page
85 GeneralPage (wxSize panel_size, int border)
86 : wxStockPreferencesPage (Kind_General)
87 , Page (panel_size, border)
90 , _num_local_encoding_threads (0)
91 , _check_for_updates (0)
92 , _check_for_test_updates (0)
95 wxWindow* CreateWindow (wxWindow* parent)
97 wxPanel* panel = make_panel (parent);
99 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
100 table->AddGrowableCol (1, 1);
101 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
103 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
104 table->Add (_set_language, 1);
105 _language = new wxChoice (panel, wxID_ANY);
106 _language->Append (wxT ("Deutsch"));
107 _language->Append (wxT ("English"));
108 _language->Append (wxT ("Español"));
109 _language->Append (wxT ("Français"));
110 _language->Append (wxT ("Italiano"));
111 _language->Append (wxT ("Nederlands"));
112 _language->Append (wxT ("Svenska"));
113 table->Add (_language);
115 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
116 wxFont font = restart->GetFont();
117 font.SetStyle (wxFONTSTYLE_ITALIC);
118 font.SetPointSize (font.GetPointSize() - 1);
119 restart->SetFont (font);
120 table->AddSpacer (0);
122 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
123 _num_local_encoding_threads = new wxSpinCtrl (panel);
124 table->Add (_num_local_encoding_threads, 1);
126 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
127 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
128 table->AddSpacer (0);
130 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
131 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
132 table->AddSpacer (0);
134 Config* config = Config::instance ();
136 _set_language->SetValue (config->language ());
138 if (config->language().get_value_or ("") == "fr") {
139 _language->SetSelection (3);
140 } else if (config->language().get_value_or ("") == "it") {
141 _language->SetSelection (4);
142 } else if (config->language().get_value_or ("") == "es") {
143 _language->SetSelection (2);
144 } else if (config->language().get_value_or ("") == "sv") {
145 _language->SetSelection (6);
146 } else if (config->language().get_value_or ("") == "de") {
147 _language->SetSelection (0);
148 } else if (config->language().get_value_or ("") == "nl") {
149 _language->SetSelection (5);
151 _language->SetSelection (1);
154 setup_language_sensitivity ();
156 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
157 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
159 _num_local_encoding_threads->SetRange (1, 128);
160 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
161 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
163 _check_for_updates->SetValue (config->check_for_updates ());
164 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
165 _check_for_test_updates->SetValue (config->check_for_test_updates ());
166 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
172 void setup_language_sensitivity ()
174 _language->Enable (_set_language->GetValue ());
177 void set_language_changed ()
179 setup_language_sensitivity ();
180 if (_set_language->GetValue ()) {
183 Config::instance()->unset_language ();
187 void language_changed ()
189 switch (_language->GetSelection ()) {
191 Config::instance()->set_language ("de");
194 Config::instance()->set_language ("en");
197 Config::instance()->set_language ("es");
200 Config::instance()->set_language ("fr");
203 Config::instance()->set_language ("it");
206 Config::instance()->set_language ("nl");
209 Config::instance()->set_language ("sv");
214 void check_for_updates_changed ()
216 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
219 void check_for_test_updates_changed ()
221 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
224 void num_local_encoding_threads_changed ()
226 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
229 wxCheckBox* _set_language;
231 wxSpinCtrl* _num_local_encoding_threads;
232 wxCheckBox* _check_for_updates;
233 wxCheckBox* _check_for_test_updates;
236 class DefaultsPage : public wxPreferencesPage, public Page
239 DefaultsPage (wxSize panel_size, int border)
240 : Page (panel_size, border)
243 , _isdcf_metadata_button (0)
247 , _dcp_content_type (0)
251 wxString GetName () const
253 return _("Defaults");
257 wxBitmap GetLargeIcon () const
259 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
263 wxWindow* CreateWindow (wxWindow* parent)
265 wxPanel* panel = make_panel (parent);
267 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
268 table->AddGrowableCol (1, 1);
269 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
272 add_label_to_sizer (table, panel, _("Default duration of still images"), true);
273 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
274 _still_length = new wxSpinCtrl (panel);
275 s->Add (_still_length);
276 add_label_to_sizer (s, panel, _("s"), false);
280 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
281 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
282 _directory = new DirPickerCtrl (panel);
284 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
286 table->Add (_directory, 1, wxEXPAND);
288 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
289 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
290 table->Add (_isdcf_metadata_button);
292 add_label_to_sizer (table, panel, _("Default container"), true);
293 _container = new wxChoice (panel, wxID_ANY);
294 table->Add (_container);
296 add_label_to_sizer (table, panel, _("Default content type"), true);
297 _dcp_content_type = new wxChoice (panel, wxID_ANY);
298 table->Add (_dcp_content_type);
301 add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
302 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
303 _j2k_bandwidth = new wxSpinCtrl (panel);
304 s->Add (_j2k_bandwidth);
305 add_label_to_sizer (s, panel, _("Mbit/s"), false);
310 add_label_to_sizer (table, panel, _("Default audio delay"), true);
311 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
312 _audio_delay = new wxSpinCtrl (panel);
313 s->Add (_audio_delay);
314 add_label_to_sizer (s, panel, _("ms"), false);
318 add_label_to_sizer (table, panel, _("Default issuer"), true);
319 _issuer = new wxTextCtrl (panel, wxID_ANY);
320 table->Add (_issuer, 1, wxEXPAND);
322 Config* config = Config::instance ();
324 _still_length->SetRange (1, 3600);
325 _still_length->SetValue (config->default_still_length ());
326 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
328 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
329 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
331 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
333 vector<Ratio const *> ratios = Ratio::all ();
334 for (size_t i = 0; i < ratios.size(); ++i) {
335 _container->Append (std_to_wx (ratios[i]->nickname ()));
336 if (ratios[i] == config->default_container ()) {
337 _container->SetSelection (i);
341 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
343 vector<DCPContentType const *> const ct = DCPContentType::all ();
344 for (size_t i = 0; i < ct.size(); ++i) {
345 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
346 if (ct[i] == config->default_dcp_content_type ()) {
347 _dcp_content_type->SetSelection (i);
351 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
353 _j2k_bandwidth->SetRange (50, 250);
354 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
355 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
357 _audio_delay->SetRange (-1000, 1000);
358 _audio_delay->SetValue (config->default_audio_delay ());
359 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
361 _issuer->SetValue (std_to_wx (config->dcp_issuer ()));
362 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
364 _config_connection = config->Changed.connect (boost::bind (&DefaultsPage::config_changed, this));
370 void config_changed ()
372 _j2k_bandwidth->SetRange (50, Config::instance()->maximum_j2k_bandwidth() / 1000000);
375 void j2k_bandwidth_changed ()
377 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
380 void audio_delay_changed ()
382 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
385 void directory_changed ()
387 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
390 void edit_isdcf_metadata_clicked (wxWindow* parent)
392 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
394 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
398 void still_length_changed ()
400 Config::instance()->set_default_still_length (_still_length->GetValue ());
403 void container_changed ()
405 vector<Ratio const *> ratio = Ratio::all ();
406 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
409 void dcp_content_type_changed ()
411 vector<DCPContentType const *> ct = DCPContentType::all ();
412 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
415 void issuer_changed ()
417 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
420 wxSpinCtrl* _j2k_bandwidth;
421 wxSpinCtrl* _audio_delay;
422 wxButton* _isdcf_metadata_button;
423 wxSpinCtrl* _still_length;
424 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
425 DirPickerCtrl* _directory;
427 wxDirPickerCtrl* _directory;
429 wxChoice* _container;
430 wxChoice* _dcp_content_type;
433 boost::signals2::scoped_connection _config_connection;
436 class EncodingServersPage : public wxPreferencesPage, public Page
439 EncodingServersPage (wxSize panel_size, int border)
440 : Page (panel_size, border)
441 , _use_any_servers (0)
445 wxString GetName () const
451 wxBitmap GetLargeIcon () const
453 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
457 wxWindow* CreateWindow (wxWindow* parent)
459 wxPanel* panel = make_panel (parent);
461 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
462 panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
464 vector<string> columns;
465 columns.push_back (wx_to_std (_("IP address / host name")));
466 _servers_list = new EditableList<string, ServerDialog> (
469 boost::bind (&Config::servers, Config::instance()),
470 boost::bind (&Config::set_servers, Config::instance(), _1),
471 boost::bind (&EncodingServersPage::server_column, this, _1)
474 panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
476 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
477 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
484 void use_any_servers_changed ()
486 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
489 string server_column (string s)
494 wxCheckBox* _use_any_servers;
495 EditableList<string, ServerDialog>* _servers_list;
498 class ColourConversionsPage : public wxPreferencesPage, public Page
501 ColourConversionsPage (wxSize panel_size, int border)
502 : Page (panel_size, border)
505 wxString GetName () const
507 return _("Colour Conversions");
511 wxBitmap GetLargeIcon () const
513 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
516 wxWindow* CreateWindow (wxWindow* parent)
518 wxPanel* panel = make_panel (parent);
520 vector<string> columns;
521 columns.push_back (wx_to_std (_("Name")));
522 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
525 boost::bind (&Config::colour_conversions, Config::instance()),
526 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
527 boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
531 panel->GetSizer()->Add (list, 1, wxEXPAND | wxALL, _border);
536 string colour_conversion_column (PresetColourConversion c)
542 class KeysPage : public wxPreferencesPage, public Page
545 KeysPage (wxSize panel_size, int border)
546 : Page (panel_size, border)
549 , _add_certificate (0)
550 , _remove_certificate (0)
551 , _remake_certificates (0)
552 , _signer_private_key (0)
553 , _load_signer_private_key (0)
554 , _decryption_certificate (0)
555 , _load_decryption_certificate (0)
556 , _decryption_private_key (0)
557 , _load_decryption_private_key (0)
558 , _export_decryption_certificate (0)
561 wxString GetName () const
567 wxBitmap GetLargeIcon () const
569 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
573 wxWindow* CreateWindow (wxWindow* parent)
575 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
576 wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
577 _panel->SetSizer (overall_sizer);
579 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Certificate chain for signing DCPs and KDMs:"));
580 overall_sizer->Add (m, 0, wxALL, _border);
582 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
583 overall_sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
585 _certificates = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (400, 200), wxLC_REPORT | wxLC_SINGLE_SEL);
590 ip.SetText (_("Type"));
592 _certificates->InsertColumn (0, ip);
598 ip.SetText (_("Thumbprint"));
601 wxFont font = ip.GetFont ();
602 font.SetFamily (wxFONTFAMILY_TELETYPE);
605 _certificates->InsertColumn (1, ip);
608 certificates_sizer->Add (_certificates, 1, wxEXPAND);
611 wxSizer* s = new wxBoxSizer (wxVERTICAL);
612 _add_certificate = new wxButton (_panel, wxID_ANY, _("Add..."));
613 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
614 _remove_certificate = new wxButton (_panel, wxID_ANY, _("Remove"));
615 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
616 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
619 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
620 table->AddGrowableCol (1, 1);
621 overall_sizer->Add (table, 1, wxALL | wxEXPAND, _border);
623 _remake_certificates = new wxButton (_panel, wxID_ANY, _("Re-make certificates..."));
624 table->Add (_remake_certificates, 0);
625 table->AddSpacer (0);
627 add_label_to_sizer (table, _panel, _("Private key for leaf certificate"), true);
629 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
630 _signer_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
631 wxFont font = _signer_private_key->GetFont ();
632 font.SetFamily (wxFONTFAMILY_TELETYPE);
633 _signer_private_key->SetFont (font);
634 s->Add (_signer_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
635 _load_signer_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
636 s->Add (_load_signer_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
640 add_label_to_sizer (table, _panel, _("Certificate for decrypting DCPs"), true);
642 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
643 _decryption_certificate = new wxStaticText (_panel, wxID_ANY, wxT (""));
644 wxFont font = _decryption_certificate->GetFont ();
645 font.SetFamily (wxFONTFAMILY_TELETYPE);
646 _decryption_certificate->SetFont (font);
647 s->Add (_decryption_certificate, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
648 _load_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Load..."));
649 s->Add (_load_decryption_certificate, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
653 add_label_to_sizer (table, _panel, _("Private key for decrypting DCPs"), true);
655 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
656 _decryption_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
657 wxFont font = _decryption_private_key->GetFont ();
658 font.SetFamily (wxFONTFAMILY_TELETYPE);
659 _decryption_private_key->SetFont (font);
660 s->Add (_decryption_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
661 _load_decryption_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
662 s->Add (_load_decryption_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
666 _export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export DCP decryption certificate..."));
667 table->Add (_export_decryption_certificate);
668 table->AddSpacer (0);
670 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::add_certificate, this));
671 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remove_certificate, this));
672 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KeysPage::update_sensitivity, this));
673 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KeysPage::update_sensitivity, this));
674 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remake_certificates, this));
675 _load_signer_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_signer_private_key, this));
676 _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
677 _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
678 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
680 _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
682 update_certificate_list ();
683 update_signer_private_key ();
684 update_decryption_certificate ();
685 update_decryption_private_key ();
686 update_sensitivity ();
692 void add_certificate ()
694 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
696 if (d->ShowModal() == wxID_OK) {
698 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
699 _signer->certificates().add (c);
700 Config::instance()->set_signer (_signer);
701 update_certificate_list ();
702 } catch (dcp::MiscError& e) {
703 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
709 update_sensitivity ();
712 void remove_certificate ()
714 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
719 _certificates->DeleteItem (i);
720 _signer->certificates().remove (i);
721 Config::instance()->set_signer (_signer);
723 update_sensitivity ();
726 void update_certificate_list ()
728 _certificates->DeleteAllItems ();
729 dcp::CertificateChain::List certs = _signer->certificates().root_to_leaf ();
731 for (dcp::CertificateChain::List::const_iterator i = certs.begin(); i != certs.end(); ++i) {
734 _certificates->InsertItem (item);
735 _certificates->SetItem (n, 1, std_to_wx (i->thumbprint ()));
738 _certificates->SetItem (n, 0, _("Root"));
739 } else if (n == (certs.size() - 1)) {
740 _certificates->SetItem (n, 0, _("Leaf"));
742 _certificates->SetItem (n, 0, _("Intermediate"));
749 void remake_certificates ()
751 MakeSignerChainDialog* d = new MakeSignerChainDialog (_panel);
752 if (d->ShowModal () == wxID_OK) {
757 d->organisational_unit (),
758 d->root_common_name (),
759 d->intermediate_common_name (),
760 d->leaf_common_name ()
764 Config::instance()->set_signer (_signer);
765 update_certificate_list ();
766 update_signer_private_key ();
772 void update_sensitivity ()
774 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
777 void update_signer_private_key ()
779 _signer_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (_signer->key ())));
782 void load_signer_private_key ()
784 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
786 if (d->ShowModal() == wxID_OK) {
788 boost::filesystem::path p (wx_to_std (d->GetPath ()));
789 if (boost::filesystem::file_size (p) > 1024) {
790 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), std_to_wx (p.string ())));
794 _signer->set_key (dcp::file_to_string (p));
795 Config::instance()->set_signer (_signer);
796 update_signer_private_key ();
797 } catch (dcp::MiscError& e) {
798 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
804 update_sensitivity ();
808 void load_decryption_certificate ()
810 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
812 if (d->ShowModal() == wxID_OK) {
814 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
815 Config::instance()->set_decryption_certificate (c);
816 update_decryption_certificate ();
817 } catch (dcp::MiscError& e) {
818 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
825 void update_decryption_certificate ()
827 _decryption_certificate->SetLabel (std_to_wx (Config::instance()->decryption_certificate().thumbprint ()));
830 void load_decryption_private_key ()
832 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
834 if (d->ShowModal() == wxID_OK) {
836 boost::filesystem::path p (wx_to_std (d->GetPath ()));
837 Config::instance()->set_decryption_private_key (dcp::file_to_string (p));
838 update_decryption_private_key ();
839 } catch (dcp::MiscError& e) {
840 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), e.what ()));
847 void update_decryption_private_key ()
849 _decryption_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (Config::instance()->decryption_private_key())));
852 void export_decryption_certificate ()
854 wxFileDialog* d = new wxFileDialog (
855 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
856 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
859 if (d->ShowModal () == wxID_OK) {
860 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
862 throw OpenFileError (wx_to_std (d->GetPath ()));
865 string const s = Config::instance()->decryption_certificate().certificate (true);
866 fwrite (s.c_str(), 1, s.length(), f);
873 wxListCtrl* _certificates;
874 wxButton* _add_certificate;
875 wxButton* _remove_certificate;
876 wxButton* _remake_certificates;
877 wxStaticText* _signer_private_key;
878 wxButton* _load_signer_private_key;
879 wxStaticText* _decryption_certificate;
880 wxButton* _load_decryption_certificate;
881 wxStaticText* _decryption_private_key;
882 wxButton* _load_decryption_private_key;
883 wxButton* _export_decryption_certificate;
884 shared_ptr<dcp::Signer> _signer;
887 class TMSPage : public wxPreferencesPage, public Page
890 TMSPage (wxSize panel_size, int border)
891 : Page (panel_size, border)
898 wxString GetName () const
904 wxBitmap GetLargeIcon () const
906 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
910 wxWindow* CreateWindow (wxWindow* parent)
912 wxPanel* panel = make_panel (parent);
914 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
915 table->AddGrowableCol (1, 1);
916 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
918 add_label_to_sizer (table, panel, _("IP address"), true);
919 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
920 table->Add (_tms_ip, 1, wxEXPAND);
922 add_label_to_sizer (table, panel, _("Target path"), true);
923 _tms_path = new wxTextCtrl (panel, wxID_ANY);
924 table->Add (_tms_path, 1, wxEXPAND);
926 add_label_to_sizer (table, panel, _("User name"), true);
927 _tms_user = new wxTextCtrl (panel, wxID_ANY);
928 table->Add (_tms_user, 1, wxEXPAND);
930 add_label_to_sizer (table, panel, _("Password"), true);
931 _tms_password = new wxTextCtrl (panel, wxID_ANY);
932 table->Add (_tms_password, 1, wxEXPAND);
934 Config* config = Config::instance ();
936 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
937 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
938 _tms_path->SetValue (std_to_wx (config->tms_path ()));
939 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
940 _tms_user->SetValue (std_to_wx (config->tms_user ()));
941 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
942 _tms_password->SetValue (std_to_wx (config->tms_password ()));
943 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
949 void tms_ip_changed ()
951 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
954 void tms_path_changed ()
956 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
959 void tms_user_changed ()
961 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
964 void tms_password_changed ()
966 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
970 wxTextCtrl* _tms_path;
971 wxTextCtrl* _tms_user;
972 wxTextCtrl* _tms_password;
975 class KDMEmailPage : public wxPreferencesPage, public Page
979 KDMEmailPage (wxSize panel_size, int border)
980 : Page (panel_size, border)
989 , _reset_kdm_email (0)
992 wxString GetName () const
994 return _("KDM Email");
998 wxBitmap GetLargeIcon () const
1000 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1004 wxWindow* CreateWindow (wxWindow* parent)
1006 #ifdef DCPOMATIC_OSX
1007 /* We have to force both width and height of this one */
1008 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
1010 wxPanel* panel = new wxPanel (parent);
1012 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
1013 panel->SetSizer (s);
1015 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1016 table->AddGrowableCol (1, 1);
1017 panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1019 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
1020 _mail_server = new wxTextCtrl (panel, wxID_ANY);
1021 table->Add (_mail_server, 1, wxEXPAND | wxALL);
1023 add_label_to_sizer (table, panel, _("Mail user name"), true);
1024 _mail_user = new wxTextCtrl (panel, wxID_ANY);
1025 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1027 add_label_to_sizer (table, panel, _("Mail password"), true);
1028 _mail_password = new wxTextCtrl (panel, wxID_ANY);
1029 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1031 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
1032 wxFont font = plain->GetFont();
1033 font.SetStyle (wxFONTSTYLE_ITALIC);
1034 font.SetPointSize (font.GetPointSize() - 1);
1035 plain->SetFont (font);
1036 table->AddSpacer (0);
1038 add_label_to_sizer (table, panel, _("Subject"), true);
1039 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
1040 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1042 add_label_to_sizer (table, panel, _("From address"), true);
1043 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
1044 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1046 add_label_to_sizer (table, panel, _("CC address"), true);
1047 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
1048 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1050 add_label_to_sizer (table, panel, _("BCC address"), true);
1051 _kdm_bcc = new wxTextCtrl (panel, wxID_ANY);
1052 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1054 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
1055 panel->GetSizer()->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
1057 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
1058 panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1060 Config* config = Config::instance ();
1061 _mail_server->SetValue (std_to_wx (config->mail_server ()));
1062 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1063 _mail_user->SetValue (std_to_wx (config->mail_user ()));
1064 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1065 _mail_password->SetValue (std_to_wx (config->mail_password ()));
1066 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1067 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
1068 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1069 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
1070 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1071 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
1072 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
1073 _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
1074 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1075 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1076 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
1077 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1083 void mail_server_changed ()
1085 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1088 void mail_user_changed ()
1090 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1093 void mail_password_changed ()
1095 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1098 void kdm_subject_changed ()
1100 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1103 void kdm_from_changed ()
1105 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1108 void kdm_cc_changed ()
1110 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
1113 void kdm_bcc_changed ()
1115 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1118 void kdm_email_changed ()
1120 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1123 void reset_kdm_email ()
1125 Config::instance()->reset_kdm_email ();
1126 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
1129 wxTextCtrl* _mail_server;
1130 wxTextCtrl* _mail_user;
1131 wxTextCtrl* _mail_password;
1132 wxTextCtrl* _kdm_subject;
1133 wxTextCtrl* _kdm_from;
1134 wxTextCtrl* _kdm_cc;
1135 wxTextCtrl* _kdm_bcc;
1136 wxTextCtrl* _kdm_email;
1137 wxButton* _reset_kdm_email;
1140 /** @class AdvancedPage
1141 * @brief Advanced page of the preferences dialog.
1143 class AdvancedPage : public wxStockPreferencesPage, public Page
1147 AdvancedPage (wxSize panel_size, int border)
1148 : wxStockPreferencesPage (Kind_Advanced)
1149 , Page (panel_size, border)
1150 , _maximum_j2k_bandwidth (0)
1151 , _allow_any_dcp_frame_rate (0)
1158 wxWindow* CreateWindow (wxWindow* parent)
1160 wxPanel* panel = make_panel (parent);
1162 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1163 table->AddGrowableCol (1, 1);
1164 panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1167 add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
1168 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1169 _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
1170 s->Add (_maximum_j2k_bandwidth, 1);
1171 add_label_to_sizer (s, panel, _("Mbit/s"), false);
1175 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
1176 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1177 table->AddSpacer (0);
1180 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log:"));
1181 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1183 wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log"));
1184 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1188 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1189 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
1190 t->Add (_log_general, 1, wxEXPAND | wxALL);
1191 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
1192 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1193 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
1194 t->Add (_log_error, 1, wxEXPAND | wxALL);
1195 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
1196 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1197 table->Add (t, 0, wxALL, 6);
1200 #ifdef DCPOMATIC_WINDOWS
1201 _win32_console = new wxCheckBox (panel, wxID_ANY, _("Open console window"));
1202 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1203 table->AddSpacer (0);
1206 Config* config = Config::instance ();
1208 _maximum_j2k_bandwidth->SetRange (1, 1000);
1209 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
1210 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1211 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
1212 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1213 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
1214 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1215 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
1216 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1217 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
1218 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1219 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
1220 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1221 #ifdef DCPOMATIC_WINDOWS
1222 _win32_console->SetValue (config->win32_console());
1223 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1231 void maximum_j2k_bandwidth_changed ()
1233 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1236 void allow_any_dcp_frame_rate_changed ()
1238 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1244 if (_log_general->GetValue ()) {
1245 types |= Log::TYPE_GENERAL;
1247 if (_log_warning->GetValue ()) {
1248 types |= Log::TYPE_WARNING;
1250 if (_log_error->GetValue ()) {
1251 types |= Log::TYPE_ERROR;
1253 if (_log_timing->GetValue ()) {
1254 types |= Log::TYPE_TIMING;
1256 Config::instance()->set_log_types (types);
1259 #ifdef DCPOMATIC_WINDOWS
1260 void win32_console_changed ()
1262 Config::instance()->set_win32_console (_win32_console->GetValue ());
1266 wxSpinCtrl* _maximum_j2k_bandwidth;
1267 wxCheckBox* _allow_any_dcp_frame_rate;
1268 wxCheckBox* _log_general;
1269 wxCheckBox* _log_warning;
1270 wxCheckBox* _log_error;
1271 wxCheckBox* _log_timing;
1272 #ifdef DCPOMATIC_WINDOWS
1273 wxCheckBox* _win32_console;
1277 wxPreferencesEditor*
1278 create_config_dialog ()
1280 wxPreferencesEditor* e = new wxPreferencesEditor ();
1282 #ifdef DCPOMATIC_OSX
1283 /* Width that we force some of the config panels to be on OSX so that
1284 the containing window doesn't shrink too much when we select those panels.
1285 This is obviously an unpleasant hack.
1287 wxSize ps = wxSize (520, -1);
1288 int const border = 16;
1290 wxSize ps = wxSize (-1, -1);
1291 int const border = 8;
1294 e->AddPage (new GeneralPage (ps, border));
1295 e->AddPage (new DefaultsPage (ps, border));
1296 e->AddPage (new EncodingServersPage (ps, border));
1297 e->AddPage (new ColourConversionsPage (ps, border));
1298 e->AddPage (new KeysPage (ps, border));
1299 e->AddPage (new TMSPage (ps, border));
1300 e->AddPage (new KDMEmailPage (ps, border));
1301 e->AddPage (new AdvancedPage (ps, border));