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 "config_dialog.h"
44 #include "editable_list.h"
45 #include "filter_dialog.h"
46 #include "dir_picker_ctrl.h"
47 #include "isdcf_metadata_dialog.h"
48 #include "preset_colour_conversion_dialog.h"
49 #include "server_dialog.h"
56 using boost::shared_ptr;
57 using boost::lexical_cast;
62 Page (wxSize panel_size, int border)
63 : _panel_size (panel_size)
72 class GeneralPage : public wxStockPreferencesPage, public Page
75 GeneralPage (wxSize panel_size, int border)
76 : wxStockPreferencesPage (Kind_General)
77 , Page (panel_size, border)
80 wxWindow* CreateWindow (wxWindow* parent)
82 wxPanel* panel = new wxPanel (parent);
83 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
86 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
87 table->AddGrowableCol (1, 1);
88 s->Add (table, 1, wxALL | wxEXPAND, _border);
90 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
91 table->Add (_set_language, 1);
92 _language = new wxChoice (panel, wxID_ANY);
93 _language->Append (wxT ("Deutsch"));
94 _language->Append (wxT ("English"));
95 _language->Append (wxT ("Español"));
96 _language->Append (wxT ("Français"));
97 _language->Append (wxT ("Italiano"));
98 _language->Append (wxT ("Nederlands"));
99 _language->Append (wxT ("Svenska"));
100 table->Add (_language);
102 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
103 wxFont font = restart->GetFont();
104 font.SetStyle (wxFONTSTYLE_ITALIC);
105 font.SetPointSize (font.GetPointSize() - 1);
106 restart->SetFont (font);
107 table->AddSpacer (0);
109 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
110 _num_local_encoding_threads = new wxSpinCtrl (panel);
111 table->Add (_num_local_encoding_threads, 1);
113 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
114 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
115 table->AddSpacer (0);
117 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
118 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
119 table->AddSpacer (0);
121 Config* config = Config::instance ();
123 _set_language->SetValue (config->language ());
125 if (config->language().get_value_or ("") == "fr") {
126 _language->SetSelection (3);
127 } else if (config->language().get_value_or ("") == "it") {
128 _language->SetSelection (4);
129 } else if (config->language().get_value_or ("") == "es") {
130 _language->SetSelection (2);
131 } else if (config->language().get_value_or ("") == "sv") {
132 _language->SetSelection (6);
133 } else if (config->language().get_value_or ("") == "de") {
134 _language->SetSelection (0);
135 } else if (config->language().get_value_or ("") == "nl") {
136 _language->SetSelection (5);
138 _language->SetSelection (1);
141 setup_language_sensitivity ();
143 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
144 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
146 _num_local_encoding_threads->SetRange (1, 128);
147 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
148 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
150 _check_for_updates->SetValue (config->check_for_updates ());
151 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
152 _check_for_test_updates->SetValue (config->check_for_test_updates ());
153 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
159 void setup_language_sensitivity ()
161 _language->Enable (_set_language->GetValue ());
164 void set_language_changed ()
166 setup_language_sensitivity ();
167 if (_set_language->GetValue ()) {
170 Config::instance()->unset_language ();
174 void language_changed ()
176 switch (_language->GetSelection ()) {
178 Config::instance()->set_language ("de");
181 Config::instance()->set_language ("en");
184 Config::instance()->set_language ("es");
187 Config::instance()->set_language ("fr");
190 Config::instance()->set_language ("it");
193 Config::instance()->set_language ("nl");
196 Config::instance()->set_language ("sv");
201 void check_for_updates_changed ()
203 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
206 void check_for_test_updates_changed ()
208 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
211 void num_local_encoding_threads_changed ()
213 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
216 wxCheckBox* _set_language;
218 wxSpinCtrl* _num_local_encoding_threads;
219 wxCheckBox* _check_for_updates;
220 wxCheckBox* _check_for_test_updates;
223 class DefaultsPage : public wxPreferencesPage, public Page
226 DefaultsPage (wxSize panel_size, int border)
227 : Page (panel_size, border)
230 wxString GetName () const
232 return _("Defaults");
236 wxBitmap GetLargeIcon () const
238 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
242 wxWindow* CreateWindow (wxWindow* parent)
244 wxPanel* panel = new wxPanel (parent);
245 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
248 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
249 table->AddGrowableCol (1, 1);
250 s->Add (table, 1, wxALL | wxEXPAND, _border);
253 add_label_to_sizer (table, panel, _("Default duration of still images"), true);
254 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
255 _still_length = new wxSpinCtrl (panel);
256 s->Add (_still_length);
257 add_label_to_sizer (s, panel, _("s"), false);
261 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
262 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
263 _directory = new DirPickerCtrl (panel);
265 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
267 table->Add (_directory, 1, wxEXPAND);
269 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
270 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
271 table->Add (_isdcf_metadata_button);
273 add_label_to_sizer (table, panel, _("Default scale to"), true);
274 _scale = new wxChoice (panel, wxID_ANY);
277 add_label_to_sizer (table, panel, _("Default container"), true);
278 _container = new wxChoice (panel, wxID_ANY);
279 table->Add (_container);
281 add_label_to_sizer (table, panel, _("Default content type"), true);
282 _dcp_content_type = new wxChoice (panel, wxID_ANY);
283 table->Add (_dcp_content_type);
286 add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
287 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
288 _j2k_bandwidth = new wxSpinCtrl (panel);
289 s->Add (_j2k_bandwidth);
290 add_label_to_sizer (s, panel, _("Mbit/s"), false);
295 add_label_to_sizer (table, panel, _("Default audio delay"), true);
296 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
297 _audio_delay = new wxSpinCtrl (panel);
298 s->Add (_audio_delay);
299 add_label_to_sizer (s, panel, _("ms"), false);
303 add_label_to_sizer (table, panel, _("Default issuer"), true);
304 _issuer = new wxTextCtrl (panel, wxID_ANY);
305 table->Add (_issuer, 1, wxEXPAND);
307 add_label_to_sizer (table, panel, _("Default creator"), true);
308 _creator = new wxTextCtrl (panel, wxID_ANY);
309 table->Add (_creator, 1, wxEXPAND);
311 Config* config = Config::instance ();
313 _still_length->SetRange (1, 3600);
314 _still_length->SetValue (config->default_still_length ());
315 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
317 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
318 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
320 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
322 vector<Ratio const *> ratio = Ratio::all ();
324 for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
325 _scale->Append (std_to_wx ((*i)->nickname ()));
326 if (*i == config->default_scale ()) {
327 _scale->SetSelection (n);
329 _container->Append (std_to_wx ((*i)->nickname ()));
330 if (*i == config->default_container ()) {
331 _container->SetSelection (n);
336 _scale->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::scale_changed, this));
337 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
339 vector<DCPContentType const *> const ct = DCPContentType::all ();
341 for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
342 _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
343 if (*i == config->default_dcp_content_type ()) {
344 _dcp_content_type->SetSelection (n);
349 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
351 _j2k_bandwidth->SetRange (50, 250);
352 _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
353 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
355 _audio_delay->SetRange (-1000, 1000);
356 _audio_delay->SetValue (config->default_audio_delay ());
357 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
359 _issuer->SetValue (std_to_wx (config->dcp_metadata().issuer));
360 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
361 _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
362 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::creator_changed, this));
368 void j2k_bandwidth_changed ()
370 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
373 void audio_delay_changed ()
375 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
378 void directory_changed ()
380 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
383 void edit_isdcf_metadata_clicked (wxWindow* parent)
385 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
387 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
391 void still_length_changed ()
393 Config::instance()->set_default_still_length (_still_length->GetValue ());
396 void scale_changed ()
398 vector<Ratio const *> ratio = Ratio::all ();
399 Config::instance()->set_default_scale (ratio[_scale->GetSelection()]);
402 void container_changed ()
404 vector<Ratio const *> ratio = Ratio::all ();
405 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
408 void dcp_content_type_changed ()
410 vector<DCPContentType const *> ct = DCPContentType::all ();
411 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
414 void issuer_changed ()
416 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
417 m.issuer = wx_to_std (_issuer->GetValue ());
418 Config::instance()->set_dcp_metadata (m);
421 void creator_changed ()
423 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
424 m.creator = wx_to_std (_creator->GetValue ());
425 Config::instance()->set_dcp_metadata (m);
428 wxSpinCtrl* _j2k_bandwidth;
429 wxSpinCtrl* _audio_delay;
430 wxButton* _isdcf_metadata_button;
431 wxSpinCtrl* _still_length;
432 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
433 DirPickerCtrl* _directory;
435 wxDirPickerCtrl* _directory;
438 wxChoice* _container;
439 wxChoice* _dcp_content_type;
441 wxTextCtrl* _creator;
444 class EncodingServersPage : public wxPreferencesPage, public Page
447 EncodingServersPage (wxSize panel_size, int border)
448 : Page (panel_size, border)
451 wxString GetName () const
457 wxBitmap GetLargeIcon () const
459 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
463 wxWindow* CreateWindow (wxWindow* parent)
465 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
466 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
469 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
470 s->Add (_use_any_servers, 0, wxALL, _border);
472 vector<string> columns;
473 columns.push_back (wx_to_std (_("IP address / host name")));
474 _servers_list = new EditableList<string, ServerDialog> (
477 boost::bind (&Config::servers, Config::instance()),
478 boost::bind (&Config::set_servers, Config::instance(), _1),
479 boost::bind (&EncodingServersPage::server_column, this, _1)
482 s->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
484 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
485 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
492 void use_any_servers_changed ()
494 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
497 string server_column (string s)
502 wxCheckBox* _use_any_servers;
503 EditableList<string, ServerDialog>* _servers_list;
506 class ColourConversionsPage : public wxPreferencesPage, public Page
509 ColourConversionsPage (wxSize panel_size, int border)
510 : Page (panel_size, border)
513 wxString GetName () const
515 return _("Colour Conversions");
519 wxBitmap GetLargeIcon () const
521 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
524 wxWindow* CreateWindow (wxWindow* parent)
526 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
527 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
530 vector<string> columns;
531 columns.push_back (wx_to_std (_("Name")));
532 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
535 boost::bind (&Config::colour_conversions, Config::instance()),
536 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
537 boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
541 s->Add (list, 1, wxEXPAND | wxALL, _border);
546 string colour_conversion_column (PresetColourConversion c)
552 class KeysPage : public wxPreferencesPage, public Page
555 KeysPage (wxSize panel_size, int border)
556 : Page (panel_size, border)
559 wxString GetName () const
565 wxBitmap GetLargeIcon () const
567 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
571 wxWindow* CreateWindow (wxWindow* parent)
573 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
574 wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
575 _panel->SetSizer (overall_sizer);
577 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Certificate chain for signing DCPs and KDMs:"));
578 overall_sizer->Add (m, 0, wxALL, _border);
580 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
581 overall_sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
583 _certificates = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (400, 200), wxLC_REPORT | wxLC_SINGLE_SEL);
588 ip.SetText (_("Type"));
590 _certificates->InsertColumn (0, ip);
596 ip.SetText (_("Thumbprint"));
599 wxFont font = ip.GetFont ();
600 font.SetFamily (wxFONTFAMILY_TELETYPE);
603 _certificates->InsertColumn (1, ip);
606 certificates_sizer->Add (_certificates, 1, wxEXPAND);
609 wxSizer* s = new wxBoxSizer (wxVERTICAL);
610 _add_certificate = new wxButton (_panel, wxID_ANY, _("Add..."));
611 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
612 _remove_certificate = new wxButton (_panel, wxID_ANY, _("Remove"));
613 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
614 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
617 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
618 table->AddGrowableCol (1, 1);
619 overall_sizer->Add (table, 1, wxALL | wxEXPAND, _border);
621 add_label_to_sizer (table, _panel, _("Private key for leaf certificate"), true);
623 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
624 _signer_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
625 wxFont font = _signer_private_key->GetFont ();
626 font.SetFamily (wxFONTFAMILY_TELETYPE);
627 _signer_private_key->SetFont (font);
628 s->Add (_signer_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
629 _load_signer_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
630 s->Add (_load_signer_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
634 add_label_to_sizer (table, _panel, _("Certificate for decrypting DCPs"), true);
636 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
637 _decryption_certificate = new wxStaticText (_panel, wxID_ANY, wxT (""));
638 wxFont font = _decryption_certificate->GetFont ();
639 font.SetFamily (wxFONTFAMILY_TELETYPE);
640 _decryption_certificate->SetFont (font);
641 s->Add (_decryption_certificate, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
642 _load_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Load..."));
643 s->Add (_load_decryption_certificate, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
647 add_label_to_sizer (table, _panel, _("Private key for decrypting DCPs"), true);
649 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
650 _decryption_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
651 wxFont font = _decryption_private_key->GetFont ();
652 font.SetFamily (wxFONTFAMILY_TELETYPE);
653 _decryption_private_key->SetFont (font);
654 s->Add (_decryption_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
655 _load_decryption_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
656 s->Add (_load_decryption_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
660 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::add_certificate, this));
661 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remove_certificate, this));
662 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KeysPage::update_sensitivity, this));
663 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KeysPage::update_sensitivity, this));
664 _load_signer_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_signer_private_key, this));
665 _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
666 _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
668 _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
670 update_certificate_list ();
671 update_signer_private_key ();
672 update_decryption_certificate ();
673 update_decryption_private_key ();
674 update_sensitivity ();
680 void add_certificate ()
682 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
684 if (d->ShowModal() == wxID_OK) {
686 shared_ptr<dcp::Certificate> c (new dcp::Certificate (dcp::file_to_string (wx_to_std (d->GetPath ()))));
687 _signer->certificates().add (c);
688 Config::instance()->set_signer (_signer);
689 update_certificate_list ();
690 } catch (dcp::MiscError& e) {
691 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
697 update_sensitivity ();
700 void remove_certificate ()
702 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
707 _certificates->DeleteItem (i);
708 _signer->certificates().remove (i);
709 Config::instance()->set_signer (_signer);
711 update_sensitivity ();
714 void update_certificate_list ()
716 _certificates->DeleteAllItems ();
717 dcp::CertificateChain::List certs = _signer->certificates().root_to_leaf ();
719 for (dcp::CertificateChain::List::const_iterator i = certs.begin(); i != certs.end(); ++i) {
722 _certificates->InsertItem (item);
723 _certificates->SetItem (n, 1, std_to_wx ((*i)->thumbprint ()));
726 _certificates->SetItem (n, 0, _("Root"));
727 } else if (n == (certs.size() - 1)) {
728 _certificates->SetItem (n, 0, _("Leaf"));
730 _certificates->SetItem (n, 0, _("Intermediate"));
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())));
818 wxListCtrl* _certificates;
819 wxButton* _add_certificate;
820 wxButton* _remove_certificate;
821 wxStaticText* _signer_private_key;
822 wxButton* _load_signer_private_key;
823 wxStaticText* _decryption_certificate;
824 wxButton* _load_decryption_certificate;
825 wxStaticText* _decryption_private_key;
826 wxButton* _load_decryption_private_key;
827 shared_ptr<dcp::Signer> _signer;
830 class TMSPage : public wxPreferencesPage, public Page
833 TMSPage (wxSize panel_size, int border)
834 : Page (panel_size, border)
837 wxString GetName () const
843 wxBitmap GetLargeIcon () const
845 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
849 wxWindow* CreateWindow (wxWindow* parent)
851 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
852 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
855 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
856 table->AddGrowableCol (1, 1);
857 s->Add (table, 1, wxALL | wxEXPAND, _border);
859 add_label_to_sizer (table, panel, _("IP address"), true);
860 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
861 table->Add (_tms_ip, 1, wxEXPAND);
863 add_label_to_sizer (table, panel, _("Target path"), true);
864 _tms_path = new wxTextCtrl (panel, wxID_ANY);
865 table->Add (_tms_path, 1, wxEXPAND);
867 add_label_to_sizer (table, panel, _("User name"), true);
868 _tms_user = new wxTextCtrl (panel, wxID_ANY);
869 table->Add (_tms_user, 1, wxEXPAND);
871 add_label_to_sizer (table, panel, _("Password"), true);
872 _tms_password = new wxTextCtrl (panel, wxID_ANY);
873 table->Add (_tms_password, 1, wxEXPAND);
875 Config* config = Config::instance ();
877 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
878 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
879 _tms_path->SetValue (std_to_wx (config->tms_path ()));
880 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
881 _tms_user->SetValue (std_to_wx (config->tms_user ()));
882 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
883 _tms_password->SetValue (std_to_wx (config->tms_password ()));
884 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
890 void tms_ip_changed ()
892 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
895 void tms_path_changed ()
897 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
900 void tms_user_changed ()
902 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
905 void tms_password_changed ()
907 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
911 wxTextCtrl* _tms_path;
912 wxTextCtrl* _tms_user;
913 wxTextCtrl* _tms_password;
916 class KDMEmailPage : public wxPreferencesPage, public Page
920 KDMEmailPage (wxSize panel_size, int border)
921 : Page (panel_size, border)
924 wxString GetName () const
926 return _("KDM Email");
930 wxBitmap GetLargeIcon () const
932 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
936 wxWindow* CreateWindow (wxWindow* parent)
938 /* We have to force both width and height of this one */
940 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
942 wxPanel* panel = new wxPanel (parent);
944 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
947 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
948 table->AddGrowableCol (1, 1);
949 s->Add (table, 1, wxEXPAND | wxALL, _border);
951 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
952 _mail_server = new wxTextCtrl (panel, wxID_ANY);
953 table->Add (_mail_server, 1, wxEXPAND | wxALL);
955 add_label_to_sizer (table, panel, _("Mail user name"), true);
956 _mail_user = new wxTextCtrl (panel, wxID_ANY);
957 table->Add (_mail_user, 1, wxEXPAND | wxALL);
959 add_label_to_sizer (table, panel, _("Mail password"), true);
960 _mail_password = new wxTextCtrl (panel, wxID_ANY);
961 table->Add (_mail_password, 1, wxEXPAND | wxALL);
963 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
964 wxFont font = plain->GetFont();
965 font.SetStyle (wxFONTSTYLE_ITALIC);
966 font.SetPointSize (font.GetPointSize() - 1);
967 plain->SetFont (font);
968 table->AddSpacer (0);
970 add_label_to_sizer (table, panel, _("Subject"), true);
971 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
972 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
974 add_label_to_sizer (table, panel, _("From address"), true);
975 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
976 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
978 add_label_to_sizer (table, panel, _("CC address"), true);
979 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
980 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
982 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
983 s->Add (_kdm_email, 1.5, wxEXPAND | wxALL, _border);
985 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
986 s->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
988 Config* config = Config::instance ();
989 _mail_server->SetValue (std_to_wx (config->mail_server ()));
990 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
991 _mail_user->SetValue (std_to_wx (config->mail_user ()));
992 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
993 _mail_password->SetValue (std_to_wx (config->mail_password ()));
994 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
995 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
996 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
997 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
998 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
999 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
1000 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
1001 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1002 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
1003 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1009 void mail_server_changed ()
1011 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1014 void mail_user_changed ()
1016 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1019 void mail_password_changed ()
1021 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1024 void kdm_subject_changed ()
1026 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1029 void kdm_from_changed ()
1031 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1034 void kdm_cc_changed ()
1036 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
1039 void kdm_email_changed ()
1041 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1044 void reset_kdm_email ()
1046 Config::instance()->reset_kdm_email ();
1047 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
1050 wxTextCtrl* _mail_server;
1051 wxTextCtrl* _mail_user;
1052 wxTextCtrl* _mail_password;
1053 wxTextCtrl* _kdm_subject;
1054 wxTextCtrl* _kdm_from;
1055 wxTextCtrl* _kdm_cc;
1056 wxTextCtrl* _kdm_email;
1057 wxButton* _reset_kdm_email;
1060 class AdvancedPage : public wxStockPreferencesPage, public Page
1064 AdvancedPage (wxSize panel_size, int border)
1065 : wxStockPreferencesPage (Kind_Advanced)
1066 , Page (panel_size, border)
1069 wxWindow* CreateWindow (wxWindow* parent)
1071 wxPanel* panel = new wxPanel (parent);
1073 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
1074 panel->SetSizer (s);
1076 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1077 table->AddGrowableCol (1, 1);
1078 s->Add (table, 1, wxALL | wxEXPAND, _border);
1081 add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
1082 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1083 _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
1084 s->Add (_maximum_j2k_bandwidth, 1);
1085 add_label_to_sizer (s, panel, _("Mbit/s"), false);
1089 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
1090 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1091 table->AddSpacer (0);
1093 add_label_to_sizer (table, panel, _("Log"), true);
1094 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
1095 table->Add (_log_general, 1, wxEXPAND | wxALL);
1096 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
1097 table->AddSpacer (0);
1098 table->Add (_log_warning, 1, wxEXPAND | wxALL);
1099 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
1100 table->AddSpacer (0);
1101 table->Add (_log_error, 1, wxEXPAND | wxALL);
1102 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
1103 table->AddSpacer (0);
1104 table->Add (_log_timing, 1, wxEXPAND | wxALL);
1106 Config* config = Config::instance ();
1108 _maximum_j2k_bandwidth->SetRange (1, 500);
1109 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
1110 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1111 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
1112 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1113 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
1114 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1115 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
1116 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1117 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
1118 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1119 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
1120 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1127 void maximum_j2k_bandwidth_changed ()
1129 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1132 void allow_any_dcp_frame_rate_changed ()
1134 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1140 if (_log_general->GetValue ()) {
1141 types |= Log::TYPE_GENERAL;
1143 if (_log_warning->GetValue ()) {
1144 types |= Log::TYPE_WARNING;
1146 if (_log_error->GetValue ()) {
1147 types |= Log::TYPE_ERROR;
1149 if (_log_timing->GetValue ()) {
1150 types |= Log::TYPE_TIMING;
1152 Config::instance()->set_log_types (types);
1155 wxSpinCtrl* _maximum_j2k_bandwidth;
1156 wxCheckBox* _allow_any_dcp_frame_rate;
1157 wxCheckBox* _log_general;
1158 wxCheckBox* _log_warning;
1159 wxCheckBox* _log_error;
1160 wxCheckBox* _log_timing;
1163 wxPreferencesEditor*
1164 create_config_dialog ()
1166 wxPreferencesEditor* e = new wxPreferencesEditor ();
1168 #ifdef DCPOMATIC_OSX
1169 /* Width that we force some of the config panels to be on OSX so that
1170 the containing window doesn't shrink too much when we select those panels.
1171 This is obviously an unpleasant hack.
1173 wxSize ps = wxSize (480, -1);
1174 int const border = 16;
1176 wxSize ps = wxSize (-1, -1);
1177 int const border = 8;
1180 e->AddPage (new GeneralPage (ps, border));
1181 e->AddPage (new DefaultsPage (ps, border));
1182 e->AddPage (new EncodingServersPage (ps, border));
1183 e->AddPage (new ColourConversionsPage (ps, border));
1184 e->AddPage (new KeysPage (ps, border));
1185 e->AddPage (new TMSPage (ps, border));
1186 e->AddPage (new KDMEmailPage (ps, border));
1187 e->AddPage (new AdvancedPage (ps, border));