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"
58 using boost::shared_ptr;
59 using boost::lexical_cast;
64 Page (wxSize panel_size, int border)
65 : _panel_size (panel_size)
74 class GeneralPage : public wxStockPreferencesPage, public Page
77 GeneralPage (wxSize panel_size, int border)
78 : wxStockPreferencesPage (Kind_General)
79 , Page (panel_size, border)
82 wxWindow* CreateWindow (wxWindow* parent)
84 wxPanel* panel = new wxPanel (parent);
85 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
88 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
89 table->AddGrowableCol (1, 1);
90 s->Add (table, 1, wxALL | wxEXPAND, _border);
92 _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
93 table->Add (_set_language, 1);
94 _language = new wxChoice (panel, wxID_ANY);
95 _language->Append (wxT ("Deutsch"));
96 _language->Append (wxT ("English"));
97 _language->Append (wxT ("Español"));
98 _language->Append (wxT ("Français"));
99 _language->Append (wxT ("Italiano"));
100 _language->Append (wxT ("Nederlands"));
101 _language->Append (wxT ("Svenska"));
102 table->Add (_language);
104 wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
105 wxFont font = restart->GetFont();
106 font.SetStyle (wxFONTSTYLE_ITALIC);
107 font.SetPointSize (font.GetPointSize() - 1);
108 restart->SetFont (font);
109 table->AddSpacer (0);
111 add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
112 _num_local_encoding_threads = new wxSpinCtrl (panel);
113 table->Add (_num_local_encoding_threads, 1);
115 _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
116 table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
117 table->AddSpacer (0);
119 _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
120 table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
121 table->AddSpacer (0);
123 Config* config = Config::instance ();
125 _set_language->SetValue (config->language ());
127 if (config->language().get_value_or ("") == "fr") {
128 _language->SetSelection (3);
129 } else if (config->language().get_value_or ("") == "it") {
130 _language->SetSelection (4);
131 } else if (config->language().get_value_or ("") == "es") {
132 _language->SetSelection (2);
133 } else if (config->language().get_value_or ("") == "sv") {
134 _language->SetSelection (6);
135 } else if (config->language().get_value_or ("") == "de") {
136 _language->SetSelection (0);
137 } else if (config->language().get_value_or ("") == "nl") {
138 _language->SetSelection (5);
140 _language->SetSelection (1);
143 setup_language_sensitivity ();
145 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
146 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
148 _num_local_encoding_threads->SetRange (1, 128);
149 _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
150 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
152 _check_for_updates->SetValue (config->check_for_updates ());
153 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
154 _check_for_test_updates->SetValue (config->check_for_test_updates ());
155 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
161 void setup_language_sensitivity ()
163 _language->Enable (_set_language->GetValue ());
166 void set_language_changed ()
168 setup_language_sensitivity ();
169 if (_set_language->GetValue ()) {
172 Config::instance()->unset_language ();
176 void language_changed ()
178 switch (_language->GetSelection ()) {
180 Config::instance()->set_language ("de");
183 Config::instance()->set_language ("en");
186 Config::instance()->set_language ("es");
189 Config::instance()->set_language ("fr");
192 Config::instance()->set_language ("it");
195 Config::instance()->set_language ("nl");
198 Config::instance()->set_language ("sv");
203 void check_for_updates_changed ()
205 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
208 void check_for_test_updates_changed ()
210 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
213 void num_local_encoding_threads_changed ()
215 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
218 wxCheckBox* _set_language;
220 wxSpinCtrl* _num_local_encoding_threads;
221 wxCheckBox* _check_for_updates;
222 wxCheckBox* _check_for_test_updates;
225 class DefaultsPage : public wxPreferencesPage, public Page
228 DefaultsPage (wxSize panel_size, int border)
229 : Page (panel_size, border)
232 wxString GetName () const
234 return _("Defaults");
238 wxBitmap GetLargeIcon () const
240 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
244 wxWindow* CreateWindow (wxWindow* parent)
246 wxPanel* panel = new wxPanel (parent);
247 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
250 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
251 table->AddGrowableCol (1, 1);
252 s->Add (table, 1, wxALL | wxEXPAND, _border);
255 add_label_to_sizer (table, panel, _("Default duration of still images"), true);
256 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
257 _still_length = new wxSpinCtrl (panel);
258 s->Add (_still_length);
259 add_label_to_sizer (s, panel, _("s"), false);
263 add_label_to_sizer (table, panel, _("Default directory for new films"), true);
264 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
265 _directory = new DirPickerCtrl (panel);
267 _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
269 table->Add (_directory, 1, wxEXPAND);
271 add_label_to_sizer (table, panel, _("Default ISDCF name details"), true);
272 _isdcf_metadata_button = new wxButton (panel, wxID_ANY, _("Edit..."));
273 table->Add (_isdcf_metadata_button);
275 add_label_to_sizer (table, panel, _("Default scale to"), true);
276 _scale = new wxChoice (panel, wxID_ANY);
279 add_label_to_sizer (table, panel, _("Default container"), true);
280 _container = new wxChoice (panel, wxID_ANY);
281 table->Add (_container);
283 add_label_to_sizer (table, panel, _("Default content type"), true);
284 _dcp_content_type = new wxChoice (panel, wxID_ANY);
285 table->Add (_dcp_content_type);
288 add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
289 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
290 _j2k_bandwidth = new wxSpinCtrl (panel);
291 s->Add (_j2k_bandwidth);
292 add_label_to_sizer (s, panel, _("Mbit/s"), false);
297 add_label_to_sizer (table, panel, _("Default audio delay"), true);
298 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
299 _audio_delay = new wxSpinCtrl (panel);
300 s->Add (_audio_delay);
301 add_label_to_sizer (s, panel, _("ms"), false);
305 add_label_to_sizer (table, panel, _("Default issuer"), true);
306 _issuer = new wxTextCtrl (panel, wxID_ANY);
307 table->Add (_issuer, 1, wxEXPAND);
309 add_label_to_sizer (table, panel, _("Default creator"), true);
310 _creator = new wxTextCtrl (panel, wxID_ANY);
311 table->Add (_creator, 1, wxEXPAND);
313 Config* config = Config::instance ();
315 _still_length->SetRange (1, 3600);
316 _still_length->SetValue (config->default_still_length ());
317 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
319 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
320 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
322 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
324 vector<Ratio const *> ratio = Ratio::all ();
326 for (vector<Ratio const *>::iterator i = ratio.begin(); i != ratio.end(); ++i) {
327 _scale->Append (std_to_wx ((*i)->nickname ()));
328 if (*i == config->default_scale ()) {
329 _scale->SetSelection (n);
331 _container->Append (std_to_wx ((*i)->nickname ()));
332 if (*i == config->default_container ()) {
333 _container->SetSelection (n);
338 _scale->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::scale_changed, this));
339 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
341 vector<DCPContentType const *> const ct = DCPContentType::all ();
343 for (vector<DCPContentType const *>::const_iterator i = ct.begin(); i != ct.end(); ++i) {
344 _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ()));
345 if (*i == config->default_dcp_content_type ()) {
346 _dcp_content_type->SetSelection (n);
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_metadata().issuer));
362 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
363 _creator->SetValue (std_to_wx (config->dcp_metadata().creator));
364 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::creator_changed, this));
370 void j2k_bandwidth_changed ()
372 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
375 void audio_delay_changed ()
377 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
380 void directory_changed ()
382 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
385 void edit_isdcf_metadata_clicked (wxWindow* parent)
387 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
389 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
393 void still_length_changed ()
395 Config::instance()->set_default_still_length (_still_length->GetValue ());
398 void scale_changed ()
400 vector<Ratio const *> ratio = Ratio::all ();
401 Config::instance()->set_default_scale (ratio[_scale->GetSelection()]);
404 void container_changed ()
406 vector<Ratio const *> ratio = Ratio::all ();
407 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
410 void dcp_content_type_changed ()
412 vector<DCPContentType const *> ct = DCPContentType::all ();
413 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
416 void issuer_changed ()
418 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
419 m.issuer = wx_to_std (_issuer->GetValue ());
420 Config::instance()->set_dcp_metadata (m);
423 void creator_changed ()
425 dcp::XMLMetadata m = Config::instance()->dcp_metadata ();
426 m.creator = wx_to_std (_creator->GetValue ());
427 Config::instance()->set_dcp_metadata (m);
430 wxSpinCtrl* _j2k_bandwidth;
431 wxSpinCtrl* _audio_delay;
432 wxButton* _isdcf_metadata_button;
433 wxSpinCtrl* _still_length;
434 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
435 DirPickerCtrl* _directory;
437 wxDirPickerCtrl* _directory;
440 wxChoice* _container;
441 wxChoice* _dcp_content_type;
443 wxTextCtrl* _creator;
446 class EncodingServersPage : public wxPreferencesPage, public Page
449 EncodingServersPage (wxSize panel_size, int border)
450 : Page (panel_size, border)
453 wxString GetName () const
459 wxBitmap GetLargeIcon () const
461 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
465 wxWindow* CreateWindow (wxWindow* parent)
467 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
468 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
471 _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
472 s->Add (_use_any_servers, 0, wxALL, _border);
474 vector<string> columns;
475 columns.push_back (wx_to_std (_("IP address / host name")));
476 _servers_list = new EditableList<string, ServerDialog> (
479 boost::bind (&Config::servers, Config::instance()),
480 boost::bind (&Config::set_servers, Config::instance(), _1),
481 boost::bind (&EncodingServersPage::server_column, this, _1)
484 s->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
486 _use_any_servers->SetValue (Config::instance()->use_any_servers ());
487 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
494 void use_any_servers_changed ()
496 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
499 string server_column (string s)
504 wxCheckBox* _use_any_servers;
505 EditableList<string, ServerDialog>* _servers_list;
508 class ColourConversionsPage : public wxPreferencesPage, public Page
511 ColourConversionsPage (wxSize panel_size, int border)
512 : Page (panel_size, border)
515 wxString GetName () const
517 return _("Colour Conversions");
521 wxBitmap GetLargeIcon () const
523 return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
526 wxWindow* CreateWindow (wxWindow* parent)
528 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
529 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
532 vector<string> columns;
533 columns.push_back (wx_to_std (_("Name")));
534 wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
537 boost::bind (&Config::colour_conversions, Config::instance()),
538 boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
539 boost::bind (&ColourConversionsPage::colour_conversion_column, this, _1),
543 s->Add (list, 1, wxEXPAND | wxALL, _border);
548 string colour_conversion_column (PresetColourConversion c)
554 class KeysPage : public wxPreferencesPage, public Page
557 KeysPage (wxSize panel_size, int border)
558 : Page (panel_size, border)
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 add_label_to_sizer (table, _panel, _("Private key for leaf certificate"), true);
625 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
626 _signer_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
627 wxFont font = _signer_private_key->GetFont ();
628 font.SetFamily (wxFONTFAMILY_TELETYPE);
629 _signer_private_key->SetFont (font);
630 s->Add (_signer_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
631 _load_signer_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
632 s->Add (_load_signer_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
636 add_label_to_sizer (table, _panel, _("Certificate for decrypting DCPs"), true);
638 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
639 _decryption_certificate = new wxStaticText (_panel, wxID_ANY, wxT (""));
640 wxFont font = _decryption_certificate->GetFont ();
641 font.SetFamily (wxFONTFAMILY_TELETYPE);
642 _decryption_certificate->SetFont (font);
643 s->Add (_decryption_certificate, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
644 _load_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Load..."));
645 s->Add (_load_decryption_certificate, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
649 add_label_to_sizer (table, _panel, _("Private key for decrypting DCPs"), true);
651 wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
652 _decryption_private_key = new wxStaticText (_panel, wxID_ANY, wxT (""));
653 wxFont font = _decryption_private_key->GetFont ();
654 font.SetFamily (wxFONTFAMILY_TELETYPE);
655 _decryption_private_key->SetFont (font);
656 s->Add (_decryption_private_key, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
657 _load_decryption_private_key = new wxButton (_panel, wxID_ANY, _("Load..."));
658 s->Add (_load_decryption_private_key, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
662 _export_decryption_certificate = new wxButton (_panel, wxID_ANY, _("Export DCP decryption certificate..."));
663 table->Add (_export_decryption_certificate);
664 table->AddSpacer (0);
666 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::add_certificate, this));
667 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::remove_certificate, this));
668 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KeysPage::update_sensitivity, this));
669 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KeysPage::update_sensitivity, this));
670 _load_signer_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_signer_private_key, this));
671 _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
672 _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
673 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
675 _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
677 update_certificate_list ();
678 update_signer_private_key ();
679 update_decryption_certificate ();
680 update_decryption_private_key ();
681 update_sensitivity ();
687 void add_certificate ()
689 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
691 if (d->ShowModal() == wxID_OK) {
693 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
694 _signer->certificates().add (c);
695 Config::instance()->set_signer (_signer);
696 update_certificate_list ();
697 } catch (dcp::MiscError& e) {
698 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
704 update_sensitivity ();
707 void remove_certificate ()
709 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
714 _certificates->DeleteItem (i);
715 _signer->certificates().remove (i);
716 Config::instance()->set_signer (_signer);
718 update_sensitivity ();
721 void update_certificate_list ()
723 _certificates->DeleteAllItems ();
724 dcp::CertificateChain::List certs = _signer->certificates().root_to_leaf ();
726 for (dcp::CertificateChain::List::const_iterator i = certs.begin(); i != certs.end(); ++i) {
729 _certificates->InsertItem (item);
730 _certificates->SetItem (n, 1, std_to_wx (i->thumbprint ()));
733 _certificates->SetItem (n, 0, _("Root"));
734 } else if (n == (certs.size() - 1)) {
735 _certificates->SetItem (n, 0, _("Leaf"));
737 _certificates->SetItem (n, 0, _("Intermediate"));
744 void update_sensitivity ()
746 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
749 void update_signer_private_key ()
751 _signer_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (_signer->key ())));
754 void load_signer_private_key ()
756 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
758 if (d->ShowModal() == wxID_OK) {
760 boost::filesystem::path p (wx_to_std (d->GetPath ()));
761 if (boost::filesystem::file_size (p) > 1024) {
762 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), std_to_wx (p.string ())));
766 _signer->set_key (dcp::file_to_string (p));
767 Config::instance()->set_signer (_signer);
768 update_signer_private_key ();
769 } catch (dcp::MiscError& e) {
770 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
776 update_sensitivity ();
780 void load_decryption_certificate ()
782 wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
784 if (d->ShowModal() == wxID_OK) {
786 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
787 Config::instance()->set_decryption_certificate (c);
788 update_decryption_certificate ();
789 } catch (dcp::MiscError& e) {
790 error_dialog (_panel, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
797 void update_decryption_certificate ()
799 _decryption_certificate->SetLabel (std_to_wx (Config::instance()->decryption_certificate().thumbprint ()));
802 void load_decryption_private_key ()
804 wxFileDialog* d = new wxFileDialog (_panel, _("Select Key File"));
806 if (d->ShowModal() == wxID_OK) {
808 boost::filesystem::path p (wx_to_std (d->GetPath ()));
809 Config::instance()->set_decryption_private_key (dcp::file_to_string (p));
810 update_decryption_private_key ();
811 } catch (dcp::MiscError& e) {
812 error_dialog (_panel, wxString::Format (_("Could not read key file (%s)"), e.what ()));
819 void update_decryption_private_key ()
821 _decryption_private_key->SetLabel (std_to_wx (dcp::private_key_fingerprint (Config::instance()->decryption_private_key())));
824 void export_decryption_certificate ()
826 wxFileDialog* d = new wxFileDialog (
827 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
828 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
831 if (d->ShowModal () == wxID_OK) {
832 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
834 throw OpenFileError (wx_to_std (d->GetPath ()));
837 string const s = Config::instance()->decryption_certificate().certificate (true);
838 fwrite (s.c_str(), 1, s.length(), f);
845 wxListCtrl* _certificates;
846 wxButton* _add_certificate;
847 wxButton* _remove_certificate;
848 wxStaticText* _signer_private_key;
849 wxButton* _load_signer_private_key;
850 wxStaticText* _decryption_certificate;
851 wxButton* _load_decryption_certificate;
852 wxStaticText* _decryption_private_key;
853 wxButton* _load_decryption_private_key;
854 wxButton* _export_decryption_certificate;
855 shared_ptr<dcp::Signer> _signer;
858 class TMSPage : public wxPreferencesPage, public Page
861 TMSPage (wxSize panel_size, int border)
862 : Page (panel_size, border)
865 wxString GetName () const
871 wxBitmap GetLargeIcon () const
873 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
877 wxWindow* CreateWindow (wxWindow* parent)
879 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
880 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
883 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
884 table->AddGrowableCol (1, 1);
885 s->Add (table, 1, wxALL | wxEXPAND, _border);
887 add_label_to_sizer (table, panel, _("IP address"), true);
888 _tms_ip = new wxTextCtrl (panel, wxID_ANY);
889 table->Add (_tms_ip, 1, wxEXPAND);
891 add_label_to_sizer (table, panel, _("Target path"), true);
892 _tms_path = new wxTextCtrl (panel, wxID_ANY);
893 table->Add (_tms_path, 1, wxEXPAND);
895 add_label_to_sizer (table, panel, _("User name"), true);
896 _tms_user = new wxTextCtrl (panel, wxID_ANY);
897 table->Add (_tms_user, 1, wxEXPAND);
899 add_label_to_sizer (table, panel, _("Password"), true);
900 _tms_password = new wxTextCtrl (panel, wxID_ANY);
901 table->Add (_tms_password, 1, wxEXPAND);
903 Config* config = Config::instance ();
905 _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
906 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
907 _tms_path->SetValue (std_to_wx (config->tms_path ()));
908 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
909 _tms_user->SetValue (std_to_wx (config->tms_user ()));
910 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
911 _tms_password->SetValue (std_to_wx (config->tms_password ()));
912 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
918 void tms_ip_changed ()
920 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
923 void tms_path_changed ()
925 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
928 void tms_user_changed ()
930 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
933 void tms_password_changed ()
935 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
939 wxTextCtrl* _tms_path;
940 wxTextCtrl* _tms_user;
941 wxTextCtrl* _tms_password;
944 class KDMEmailPage : public wxPreferencesPage, public Page
948 KDMEmailPage (wxSize panel_size, int border)
949 : Page (panel_size, border)
952 wxString GetName () const
954 return _("KDM Email");
958 wxBitmap GetLargeIcon () const
960 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
964 wxWindow* CreateWindow (wxWindow* parent)
966 /* We have to force both width and height of this one */
968 wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
970 wxPanel* panel = new wxPanel (parent);
972 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
975 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
976 table->AddGrowableCol (1, 1);
977 s->Add (table, 1, wxEXPAND | wxALL, _border);
979 add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
980 _mail_server = new wxTextCtrl (panel, wxID_ANY);
981 table->Add (_mail_server, 1, wxEXPAND | wxALL);
983 add_label_to_sizer (table, panel, _("Mail user name"), true);
984 _mail_user = new wxTextCtrl (panel, wxID_ANY);
985 table->Add (_mail_user, 1, wxEXPAND | wxALL);
987 add_label_to_sizer (table, panel, _("Mail password"), true);
988 _mail_password = new wxTextCtrl (panel, wxID_ANY);
989 table->Add (_mail_password, 1, wxEXPAND | wxALL);
991 wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
992 wxFont font = plain->GetFont();
993 font.SetStyle (wxFONTSTYLE_ITALIC);
994 font.SetPointSize (font.GetPointSize() - 1);
995 plain->SetFont (font);
996 table->AddSpacer (0);
998 add_label_to_sizer (table, panel, _("Subject"), true);
999 _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
1000 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1002 add_label_to_sizer (table, panel, _("From address"), true);
1003 _kdm_from = new wxTextCtrl (panel, wxID_ANY);
1004 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1006 add_label_to_sizer (table, panel, _("CC address"), true);
1007 _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
1008 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1010 add_label_to_sizer (table, panel, _("BCC address"), true);
1011 _kdm_bcc = new wxTextCtrl (panel, wxID_ANY);
1012 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1014 _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
1015 s->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
1017 _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
1018 s->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1020 Config* config = Config::instance ();
1021 _mail_server->SetValue (std_to_wx (config->mail_server ()));
1022 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1023 _mail_user->SetValue (std_to_wx (config->mail_user ()));
1024 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1025 _mail_password->SetValue (std_to_wx (config->mail_password ()));
1026 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1027 _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
1028 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1029 _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
1030 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1031 _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
1032 _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
1033 _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
1034 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1035 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1036 _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
1037 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1043 void mail_server_changed ()
1045 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1048 void mail_user_changed ()
1050 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1053 void mail_password_changed ()
1055 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1058 void kdm_subject_changed ()
1060 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1063 void kdm_from_changed ()
1065 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1068 void kdm_cc_changed ()
1070 Config::instance()->set_kdm_cc (wx_to_std (_kdm_cc->GetValue ()));
1073 void kdm_bcc_changed ()
1075 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1078 void kdm_email_changed ()
1080 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1083 void reset_kdm_email ()
1085 Config::instance()->reset_kdm_email ();
1086 _kdm_email->SetValue (wx_to_std (Config::instance()->kdm_email ()));
1089 wxTextCtrl* _mail_server;
1090 wxTextCtrl* _mail_user;
1091 wxTextCtrl* _mail_password;
1092 wxTextCtrl* _kdm_subject;
1093 wxTextCtrl* _kdm_from;
1094 wxTextCtrl* _kdm_cc;
1095 wxTextCtrl* _kdm_bcc;
1096 wxTextCtrl* _kdm_email;
1097 wxButton* _reset_kdm_email;
1100 class AdvancedPage : public wxStockPreferencesPage, public Page
1104 AdvancedPage (wxSize panel_size, int border)
1105 : wxStockPreferencesPage (Kind_Advanced)
1106 , Page (panel_size, border)
1109 wxWindow* CreateWindow (wxWindow* parent)
1111 wxPanel* panel = new wxPanel (parent);
1113 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
1114 panel->SetSizer (s);
1116 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1117 table->AddGrowableCol (1, 1);
1118 s->Add (table, 1, wxALL | wxEXPAND, _border);
1121 add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
1122 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1123 _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
1124 s->Add (_maximum_j2k_bandwidth, 1);
1125 add_label_to_sizer (s, panel, _("Mbit/s"), false);
1129 _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
1130 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1131 table->AddSpacer (0);
1133 add_label_to_sizer (table, panel, _("Log"), true);
1134 _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
1135 table->Add (_log_general, 1, wxEXPAND | wxALL);
1136 _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
1137 table->AddSpacer (0);
1138 table->Add (_log_warning, 1, wxEXPAND | wxALL);
1139 _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
1140 table->AddSpacer (0);
1141 table->Add (_log_error, 1, wxEXPAND | wxALL);
1142 _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
1143 table->AddSpacer (0);
1144 table->Add (_log_timing, 1, wxEXPAND | wxALL);
1146 Config* config = Config::instance ();
1148 _maximum_j2k_bandwidth->SetRange (1, 500);
1149 _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
1150 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1151 _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
1152 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1153 _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
1154 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1155 _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
1156 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1157 _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
1158 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1159 _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
1160 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1167 void maximum_j2k_bandwidth_changed ()
1169 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1172 void allow_any_dcp_frame_rate_changed ()
1174 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1180 if (_log_general->GetValue ()) {
1181 types |= Log::TYPE_GENERAL;
1183 if (_log_warning->GetValue ()) {
1184 types |= Log::TYPE_WARNING;
1186 if (_log_error->GetValue ()) {
1187 types |= Log::TYPE_ERROR;
1189 if (_log_timing->GetValue ()) {
1190 types |= Log::TYPE_TIMING;
1192 Config::instance()->set_log_types (types);
1195 wxSpinCtrl* _maximum_j2k_bandwidth;
1196 wxCheckBox* _allow_any_dcp_frame_rate;
1197 wxCheckBox* _log_general;
1198 wxCheckBox* _log_warning;
1199 wxCheckBox* _log_error;
1200 wxCheckBox* _log_timing;
1203 wxPreferencesEditor*
1204 create_config_dialog ()
1206 wxPreferencesEditor* e = new wxPreferencesEditor ();
1208 #ifdef DCPOMATIC_OSX
1209 /* Width that we force some of the config panels to be on OSX so that
1210 the containing window doesn't shrink too much when we select those panels.
1211 This is obviously an unpleasant hack.
1213 wxSize ps = wxSize (480, -1);
1214 int const border = 16;
1216 wxSize ps = wxSize (-1, -1);
1217 int const border = 8;
1220 e->AddPage (new GeneralPage (ps, border));
1221 e->AddPage (new DefaultsPage (ps, border));
1222 e->AddPage (new EncodingServersPage (ps, border));
1223 e->AddPage (new ColourConversionsPage (ps, border));
1224 e->AddPage (new KeysPage (ps, border));
1225 e->AddPage (new TMSPage (ps, border));
1226 e->AddPage (new KDMEmailPage (ps, border));
1227 e->AddPage (new AdvancedPage (ps, border));