2 Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
21 /** @file src/config_dialog.cc
22 * @brief A dialogue to edit DCP-o-matic configuration.
25 #include "config_dialog.h"
27 #include "editable_list.h"
28 #include "filter_dialog.h"
29 #include "dir_picker_ctrl.h"
30 #include "file_picker_ctrl.h"
31 #include "isdcf_metadata_dialog.h"
32 #include "server_dialog.h"
33 #include "make_chain_dialog.h"
34 #include "email_dialog.h"
35 #include "lib/config.h"
36 #include "lib/ratio.h"
37 #include "lib/filter.h"
38 #include "lib/dcp_content_type.h"
41 #include "lib/raw_convert.h"
42 #include "lib/cross.h"
43 #include "lib/exceptions.h"
44 #include <dcp/exceptions.h>
45 #include <dcp/certificate_chain.h>
46 #include <dcp/raw_convert.h>
47 #include <wx/stdpaths.h>
48 #include <wx/preferences.h>
49 #include <wx/spinctrl.h>
50 #include <wx/filepicker.h>
51 #include <boost/filesystem.hpp>
52 #include <boost/foreach.hpp>
63 using boost::shared_ptr;
64 using boost::function;
65 using boost::optional;
70 Page (wxSize panel_size, int border)
73 , _panel_size (panel_size)
74 , _window_exists (false)
76 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
82 wxWindow* create_window (wxWindow* parent)
84 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
85 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
89 _window_exists = true;
92 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
101 virtual void config_changed () = 0;
102 virtual void setup () = 0;
104 void config_changed_wrapper ()
106 if (_window_exists) {
111 void window_destroyed ()
113 _window_exists = false;
117 boost::signals2::scoped_connection _config_connection;
121 class StockPage : public wxStockPreferencesPage, public Page
124 StockPage (Kind kind, wxSize panel_size, int border)
125 : wxStockPreferencesPage (kind)
126 , Page (panel_size, border)
129 wxWindow* CreateWindow (wxWindow* parent)
131 return create_window (parent);
135 class StandardPage : public wxPreferencesPage, public Page
138 StandardPage (wxSize panel_size, int border)
139 : Page (panel_size, border)
142 wxWindow* CreateWindow (wxWindow* parent)
144 return create_window (parent);
148 class GeneralPage : public StockPage
151 GeneralPage (wxSize panel_size, int border)
152 : StockPage (Kind_General, panel_size, border)
158 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
159 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
162 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
163 table->Add (_set_language, wxGBPosition (r, 0));
164 _language = new wxChoice (_panel, wxID_ANY);
165 vector<pair<string, string> > languages;
166 languages.push_back (make_pair ("Čeština", "cs_CZ"));
167 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
168 languages.push_back (make_pair ("Dansk", "da_DK"));
169 languages.push_back (make_pair ("Deutsch", "de_DE"));
170 languages.push_back (make_pair ("English", "en_GB"));
171 languages.push_back (make_pair ("Español", "es_ES"));
172 languages.push_back (make_pair ("Français", "fr_FR"));
173 languages.push_back (make_pair ("Italiano", "it_IT"));
174 languages.push_back (make_pair ("Nederlands", "nl_NL"));
175 languages.push_back (make_pair ("Русский", "ru_RU"));
176 languages.push_back (make_pair ("Polski", "pl_PL"));
177 languages.push_back (make_pair ("Português europeu", "pt_PT"));
178 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
179 languages.push_back (make_pair ("Svenska", "sv_SE"));
180 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
181 languages.push_back (make_pair ("українська мова", "uk_UA"));
182 checked_set (_language, languages);
183 table->Add (_language, wxGBPosition (r, 1));
186 wxStaticText* restart = add_label_to_sizer (
187 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
189 wxFont font = restart->GetFont();
190 font.SetStyle (wxFONTSTYLE_ITALIC);
191 font.SetPointSize (font.GetPointSize() - 1);
192 restart->SetFont (font);
195 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
196 _num_local_encoding_threads = new wxSpinCtrl (_panel);
197 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
200 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
201 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
202 table->Add (_cinemas_file, wxGBPosition (r, 1));
205 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
206 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
207 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
211 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
212 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
215 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
216 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
219 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
220 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
223 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
224 bottom_table->AddGrowableCol (1, 1);
226 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
227 _issuer = new wxTextCtrl (_panel, wxID_ANY);
228 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
230 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
231 _creator = new wxTextCtrl (_panel, wxID_ANY);
232 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
234 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
237 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
238 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
239 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
241 _num_local_encoding_threads->SetRange (1, 128);
242 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
244 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
245 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
247 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
248 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
249 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
251 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
252 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::creator_changed, this));
255 void config_changed ()
257 Config* config = Config::instance ();
259 checked_set (_set_language, static_cast<bool>(config->language()));
261 /* Backwards compatibility of config file */
263 map<string, string> compat_map;
264 compat_map["fr"] = "fr_FR";
265 compat_map["it"] = "it_IT";
266 compat_map["es"] = "es_ES";
267 compat_map["sv"] = "sv_SE";
268 compat_map["de"] = "de_DE";
269 compat_map["nl"] = "nl_NL";
270 compat_map["ru"] = "ru_RU";
271 compat_map["pl"] = "pl_PL";
272 compat_map["da"] = "da_DK";
273 compat_map["pt"] = "pt_PT";
274 compat_map["sk"] = "sk_SK";
275 compat_map["cs"] = "cs_CZ";
276 compat_map["uk"] = "uk_UA";
278 string lang = config->language().get_value_or ("en_GB");
279 if (compat_map.find (lang) != compat_map.end ()) {
280 lang = compat_map[lang];
283 checked_set (_language, lang);
285 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
286 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
287 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
289 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
290 checked_set (_check_for_updates, config->check_for_updates ());
291 checked_set (_check_for_test_updates, config->check_for_test_updates ());
292 checked_set (_issuer, config->dcp_issuer ());
293 checked_set (_creator, config->dcp_creator ());
294 checked_set (_cinemas_file, config->cinemas_file());
296 setup_sensitivity ();
299 void setup_sensitivity ()
301 _language->Enable (_set_language->GetValue ());
302 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
305 void set_language_changed ()
307 setup_sensitivity ();
308 if (_set_language->GetValue ()) {
311 Config::instance()->unset_language ();
315 void language_changed ()
317 int const sel = _language->GetSelection ();
319 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
321 Config::instance()->unset_language ();
325 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
326 void analyse_ebur128_changed ()
328 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
332 void automatic_audio_analysis_changed ()
334 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
337 void check_for_updates_changed ()
339 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
342 void check_for_test_updates_changed ()
344 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
347 void num_local_encoding_threads_changed ()
349 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
352 void issuer_changed ()
354 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
357 void creator_changed ()
359 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
362 void cinemas_file_changed ()
364 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
367 wxCheckBox* _set_language;
369 wxSpinCtrl* _num_local_encoding_threads;
370 FilePickerCtrl* _cinemas_file;
371 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
372 wxCheckBox* _analyse_ebur128;
374 wxCheckBox* _automatic_audio_analysis;
375 wxCheckBox* _check_for_updates;
376 wxCheckBox* _check_for_test_updates;
378 wxTextCtrl* _creator;
381 class DefaultsPage : public StandardPage
384 DefaultsPage (wxSize panel_size, int border)
385 : StandardPage (panel_size, border)
388 wxString GetName () const
390 return _("Defaults");
394 wxBitmap GetLargeIcon () const
396 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
403 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
404 table->AddGrowableCol (1, 1);
405 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
408 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
409 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
410 _still_length = new wxSpinCtrl (_panel);
411 s->Add (_still_length);
412 add_label_to_sizer (s, _panel, _("s"), false);
416 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
417 #ifdef DCPOMATIC_USE_OWN_PICKER
418 _directory = new DirPickerCtrl (_panel);
420 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
422 table->Add (_directory, 1, wxEXPAND);
424 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
425 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
426 table->Add (_isdcf_metadata_button);
428 add_label_to_sizer (table, _panel, _("Default container"), true);
429 _container = new wxChoice (_panel, wxID_ANY);
430 table->Add (_container);
432 add_label_to_sizer (table, _panel, _("Default content type"), true);
433 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
434 table->Add (_dcp_content_type);
436 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
437 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
438 table->Add (_dcp_audio_channels);
441 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
442 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
443 _j2k_bandwidth = new wxSpinCtrl (_panel);
444 s->Add (_j2k_bandwidth);
445 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
450 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
451 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
452 _audio_delay = new wxSpinCtrl (_panel);
453 s->Add (_audio_delay);
454 add_label_to_sizer (s, _panel, _("ms"), false);
458 add_label_to_sizer (table, _panel, _("Default standard"), true);
459 _standard = new wxChoice (_panel, wxID_ANY);
460 table->Add (_standard);
462 _still_length->SetRange (1, 3600);
463 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
465 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
467 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
469 vector<Ratio const *> ratios = Ratio::all ();
470 for (size_t i = 0; i < ratios.size(); ++i) {
471 _container->Append (std_to_wx (ratios[i]->nickname ()));
474 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
476 vector<DCPContentType const *> const ct = DCPContentType::all ();
477 for (size_t i = 0; i < ct.size(); ++i) {
478 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
481 setup_audio_channels_choice (_dcp_audio_channels, 2);
483 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
484 _dcp_audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
486 _j2k_bandwidth->SetRange (50, 250);
487 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
489 _audio_delay->SetRange (-1000, 1000);
490 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
492 _standard->Append (_("SMPTE"));
493 _standard->Append (_("Interop"));
494 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
497 void config_changed ()
499 Config* config = Config::instance ();
501 vector<Ratio const *> ratios = Ratio::all ();
502 for (size_t i = 0; i < ratios.size(); ++i) {
503 if (ratios[i] == config->default_container ()) {
504 _container->SetSelection (i);
508 vector<DCPContentType const *> const ct = DCPContentType::all ();
509 for (size_t i = 0; i < ct.size(); ++i) {
510 if (ct[i] == config->default_dcp_content_type ()) {
511 _dcp_content_type->SetSelection (i);
515 checked_set (_still_length, config->default_still_length ());
516 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
517 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
518 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
519 checked_set (_dcp_audio_channels, raw_convert<string> (config->default_dcp_audio_channels()));
520 checked_set (_audio_delay, config->default_audio_delay ());
521 checked_set (_standard, config->default_interop() ? 1 : 0);
524 void j2k_bandwidth_changed ()
526 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
529 void audio_delay_changed ()
531 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
534 void dcp_audio_channels_changed ()
536 int const s = _dcp_audio_channels->GetSelection ();
537 if (s != wxNOT_FOUND) {
538 Config::instance()->set_default_dcp_audio_channels (dcp::raw_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s))));
542 void directory_changed ()
544 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
547 void edit_isdcf_metadata_clicked ()
549 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
551 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
555 void still_length_changed ()
557 Config::instance()->set_default_still_length (_still_length->GetValue ());
560 void container_changed ()
562 vector<Ratio const *> ratio = Ratio::all ();
563 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
566 void dcp_content_type_changed ()
568 vector<DCPContentType const *> ct = DCPContentType::all ();
569 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
572 void standard_changed ()
574 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
577 wxSpinCtrl* _j2k_bandwidth;
578 wxSpinCtrl* _audio_delay;
579 wxButton* _isdcf_metadata_button;
580 wxSpinCtrl* _still_length;
581 #ifdef DCPOMATIC_USE_OWN_PICKER
582 DirPickerCtrl* _directory;
584 wxDirPickerCtrl* _directory;
586 wxChoice* _container;
587 wxChoice* _dcp_content_type;
588 wxChoice* _dcp_audio_channels;
592 class EncodingServersPage : public StandardPage
595 EncodingServersPage (wxSize panel_size, int border)
596 : StandardPage (panel_size, border)
599 wxString GetName () const
605 wxBitmap GetLargeIcon () const
607 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
614 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
615 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
617 vector<string> columns;
618 columns.push_back (wx_to_std (_("IP address / host name")));
619 _servers_list = new EditableList<string, ServerDialog> (
622 boost::bind (&Config::servers, Config::instance()),
623 boost::bind (&Config::set_servers, Config::instance(), _1),
624 boost::bind (&always_valid),
625 boost::bind (&EncodingServersPage::server_column, this, _1)
628 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
630 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
633 void config_changed ()
635 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
636 _servers_list->refresh ();
639 void use_any_servers_changed ()
641 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
644 string server_column (string s)
649 wxCheckBox* _use_any_servers;
650 EditableList<string, ServerDialog>* _servers_list;
653 class CertificateChainEditor : public wxPanel
656 CertificateChainEditor (
660 function<void (shared_ptr<dcp::CertificateChain>)> set,
661 function<shared_ptr<const dcp::CertificateChain> (void)> get
667 wxFont subheading_font (*wxNORMAL_FONT);
668 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
670 _sizer = new wxBoxSizer (wxVERTICAL);
673 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
674 m->SetFont (subheading_font);
675 _sizer->Add (m, 0, wxALL, border);
678 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
679 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
681 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
686 ip.SetText (_("Type"));
688 _certificates->InsertColumn (0, ip);
694 ip.SetText (_("Thumbprint"));
697 wxFont font = ip.GetFont ();
698 font.SetFamily (wxFONTFAMILY_TELETYPE);
701 _certificates->InsertColumn (1, ip);
704 certificates_sizer->Add (_certificates, 1, wxEXPAND);
707 wxSizer* s = new wxBoxSizer (wxVERTICAL);
708 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
709 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
710 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
711 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
712 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
713 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
714 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
717 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
718 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
721 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
722 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
723 wxFont font = _private_key->GetFont ();
724 font.SetFamily (wxFONTFAMILY_TELETYPE);
725 _private_key->SetFont (font);
726 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
727 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
728 table->Add (_load_private_key, wxGBPosition (r, 2));
729 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
730 table->Add (_export_private_key, wxGBPosition (r, 3));
733 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
734 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates and key..."));
735 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
736 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
739 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::add_certificate, this));
740 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remove_certificate, this));
741 _export_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_certificate, this));
742 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
743 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
744 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remake_certificates, this));
745 _load_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::load_private_key, this));
746 _export_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_private_key, this));
748 SetSizerAndFit (_sizer);
751 void config_changed ()
753 _chain.reset (new dcp::CertificateChain (*_get().get ()));
755 update_certificate_list ();
756 update_private_key ();
757 update_sensitivity ();
760 void add_button (wxWindow* button)
762 _button_sizer->Add (button);
767 void add_certificate ()
769 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
771 if (d->ShowModal() == wxID_OK) {
773 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
774 if (c.extra_data ()) {
777 _("This file contains other certificates (or other data) after its first certificate. "
778 "Only the first certificate will be used.")
783 update_certificate_list ();
784 } catch (dcp::MiscError& e) {
785 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
791 update_sensitivity ();
794 void remove_certificate ()
796 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
801 _certificates->DeleteItem (i);
805 update_sensitivity ();
808 void export_certificate ()
810 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
815 wxFileDialog* d = new wxFileDialog (
816 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
817 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
820 dcp::CertificateChain::List all = _chain->root_to_leaf ();
821 dcp::CertificateChain::List::iterator j = all.begin ();
822 for (int k = 0; k < i; ++k) {
826 if (d->ShowModal () == wxID_OK) {
827 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
829 throw OpenFileError (wx_to_std (d->GetPath ()));
832 string const s = j->certificate (true);
833 fwrite (s.c_str(), 1, s.length(), f);
839 void update_certificate_list ()
841 _certificates->DeleteAllItems ();
843 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
844 BOOST_FOREACH (dcp::Certificate const & i, certs) {
847 _certificates->InsertItem (item);
848 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
851 _certificates->SetItem (n, 0, _("Root"));
852 } else if (n == (certs.size() - 1)) {
853 _certificates->SetItem (n, 0, _("Leaf"));
855 _certificates->SetItem (n, 0, _("Intermediate"));
862 void remake_certificates ()
864 shared_ptr<const dcp::CertificateChain> chain = _get ();
866 string subject_organization_name;
867 string subject_organizational_unit_name;
868 string root_common_name;
869 string intermediate_common_name;
870 string leaf_common_name;
872 dcp::CertificateChain::List all = chain->root_to_leaf ();
874 if (all.size() >= 1) {
876 subject_organization_name = chain->root().subject_organization_name ();
877 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
878 root_common_name = chain->root().subject_common_name ();
881 if (all.size() >= 2) {
883 leaf_common_name = chain->leaf().subject_common_name ();
886 if (all.size() >= 3) {
887 /* Have an intermediate */
888 dcp::CertificateChain::List::iterator i = all.begin ();
890 intermediate_common_name = i->subject_common_name ();
893 MakeChainDialog* d = new MakeChainDialog (
895 subject_organization_name,
896 subject_organizational_unit_name,
898 intermediate_common_name,
902 if (d->ShowModal () == wxID_OK) {
904 new dcp::CertificateChain (
907 d->organisational_unit (),
908 d->root_common_name (),
909 d->intermediate_common_name (),
910 d->leaf_common_name ()
915 update_certificate_list ();
916 update_private_key ();
922 void update_sensitivity ()
924 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
925 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
928 void update_private_key ()
930 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
934 void load_private_key ()
936 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
938 if (d->ShowModal() == wxID_OK) {
940 boost::filesystem::path p (wx_to_std (d->GetPath ()));
941 if (boost::filesystem::file_size (p) > 8192) {
944 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
949 _chain->set_key (dcp::file_to_string (p));
951 update_private_key ();
952 } catch (dcp::MiscError& e) {
953 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
959 update_sensitivity ();
962 void export_private_key ()
964 optional<string> key = _chain->key ();
969 wxFileDialog* d = new wxFileDialog (
970 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
971 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
974 if (d->ShowModal () == wxID_OK) {
975 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
977 throw OpenFileError (wx_to_std (d->GetPath ()));
980 string const s = _chain->key().get ();
981 fwrite (s.c_str(), 1, s.length(), f);
987 wxListCtrl* _certificates;
988 wxButton* _add_certificate;
989 wxButton* _export_certificate;
990 wxButton* _remove_certificate;
991 wxButton* _remake_certificates;
992 wxStaticText* _private_key;
993 wxButton* _load_private_key;
994 wxButton* _export_private_key;
996 wxBoxSizer* _button_sizer;
997 shared_ptr<dcp::CertificateChain> _chain;
998 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
999 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1002 class KeysPage : public StandardPage
1005 KeysPage (wxSize panel_size, int border)
1006 : StandardPage (panel_size, border)
1009 wxString GetName () const
1014 #ifdef DCPOMATIC_OSX
1015 wxBitmap GetLargeIcon () const
1017 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1025 _signer = new CertificateChainEditor (
1026 _panel, _("Signing DCPs and KDMs"), _border,
1027 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1028 boost::bind (&Config::signer_chain, Config::instance ())
1031 _panel->GetSizer()->Add (_signer);
1033 _decryption = new CertificateChainEditor (
1034 _panel, _("Decrypting DCPs"), _border,
1035 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1036 boost::bind (&Config::decryption_chain, Config::instance ())
1039 _panel->GetSizer()->Add (_decryption);
1041 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption certificate..."));
1042 _decryption->add_button (_export_decryption_certificate);
1044 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1047 void export_decryption_certificate ()
1049 wxFileDialog* d = new wxFileDialog (
1050 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1051 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1054 if (d->ShowModal () == wxID_OK) {
1055 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1057 throw OpenFileError (wx_to_std (d->GetPath ()));
1060 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1061 fwrite (s.c_str(), 1, s.length(), f);
1067 void config_changed ()
1069 _signer->config_changed ();
1070 _decryption->config_changed ();
1073 CertificateChainEditor* _signer;
1074 CertificateChainEditor* _decryption;
1075 wxButton* _export_decryption_certificate;
1078 class TMSPage : public StandardPage
1081 TMSPage (wxSize panel_size, int border)
1082 : StandardPage (panel_size, border)
1085 wxString GetName () const
1090 #ifdef DCPOMATIC_OSX
1091 wxBitmap GetLargeIcon () const
1093 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1100 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1101 table->AddGrowableCol (1, 1);
1102 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1104 add_label_to_sizer (table, _panel, _("Protocol"), true);
1105 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1106 table->Add (_tms_protocol, 1, wxEXPAND);
1108 add_label_to_sizer (table, _panel, _("IP address"), true);
1109 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1110 table->Add (_tms_ip, 1, wxEXPAND);
1112 add_label_to_sizer (table, _panel, _("Target path"), true);
1113 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1114 table->Add (_tms_path, 1, wxEXPAND);
1116 add_label_to_sizer (table, _panel, _("User name"), true);
1117 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1118 table->Add (_tms_user, 1, wxEXPAND);
1120 add_label_to_sizer (table, _panel, _("Password"), true);
1121 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1122 table->Add (_tms_password, 1, wxEXPAND);
1124 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1125 _tms_protocol->Append (_("FTP (for Dolby)"));
1127 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1128 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1129 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1130 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1131 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1134 void config_changed ()
1136 Config* config = Config::instance ();
1138 checked_set (_tms_protocol, config->tms_protocol ());
1139 checked_set (_tms_ip, config->tms_ip ());
1140 checked_set (_tms_path, config->tms_path ());
1141 checked_set (_tms_user, config->tms_user ());
1142 checked_set (_tms_password, config->tms_password ());
1145 void tms_protocol_changed ()
1147 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1150 void tms_ip_changed ()
1152 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1155 void tms_path_changed ()
1157 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1160 void tms_user_changed ()
1162 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1165 void tms_password_changed ()
1167 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1170 wxChoice* _tms_protocol;
1171 wxTextCtrl* _tms_ip;
1172 wxTextCtrl* _tms_path;
1173 wxTextCtrl* _tms_user;
1174 wxTextCtrl* _tms_password;
1183 class KDMEmailPage : public StandardPage
1187 KDMEmailPage (wxSize panel_size, int border)
1188 #ifdef DCPOMATIC_OSX
1189 /* We have to force both width and height of this one */
1190 : StandardPage (wxSize (480, 128), border)
1192 : StandardPage (panel_size, border)
1196 wxString GetName () const
1198 return _("KDM Email");
1201 #ifdef DCPOMATIC_OSX
1202 wxBitmap GetLargeIcon () const
1204 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1211 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1212 table->AddGrowableCol (1, 1);
1213 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1215 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1217 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1218 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1219 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1220 add_label_to_sizer (s, _panel, _("port"), false);
1221 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1222 _mail_port->SetRange (0, 65535);
1223 s->Add (_mail_port);
1224 table->Add (s, 1, wxEXPAND | wxALL);
1227 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1228 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1229 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1231 add_label_to_sizer (table, _panel, _("Mail password"), true);
1232 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1233 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1235 add_label_to_sizer (table, _panel, _("Subject"), true);
1236 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1237 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1239 add_label_to_sizer (table, _panel, _("From address"), true);
1240 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1241 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1243 vector<string> columns;
1244 columns.push_back (wx_to_std (_("Address")));
1245 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1246 _kdm_cc = new EditableList<string, EmailDialog> (
1249 bind (&Config::kdm_cc, Config::instance()),
1250 bind (&Config::set_kdm_cc, Config::instance(), _1),
1251 bind (&string_not_empty, _1),
1254 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1256 add_label_to_sizer (table, _panel, _("BCC address"), true);
1257 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1258 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1260 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1261 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1263 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1264 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1268 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1269 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1270 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1271 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1272 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1273 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1274 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1275 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1276 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1279 void config_changed ()
1281 Config* config = Config::instance ();
1283 checked_set (_mail_server, config->mail_server ());
1284 checked_set (_mail_port, config->mail_port ());
1285 checked_set (_mail_user, config->mail_user ());
1286 checked_set (_mail_password, config->mail_password ());
1287 checked_set (_kdm_subject, config->kdm_subject ());
1288 checked_set (_kdm_from, config->kdm_from ());
1289 checked_set (_kdm_bcc, config->kdm_bcc ());
1290 checked_set (_kdm_email, Config::instance()->kdm_email ());
1293 void mail_server_changed ()
1295 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1298 void mail_port_changed ()
1300 Config::instance()->set_mail_port (_mail_port->GetValue ());
1303 void mail_user_changed ()
1305 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1308 void mail_password_changed ()
1310 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1313 void kdm_subject_changed ()
1315 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1318 void kdm_from_changed ()
1320 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1323 void kdm_bcc_changed ()
1325 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1328 void kdm_email_changed ()
1330 if (_kdm_email->GetValue().IsEmpty ()) {
1331 /* Sometimes we get sent an erroneous notification that the email
1332 is empty; I don't know why.
1336 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1339 void reset_kdm_email ()
1341 Config::instance()->reset_kdm_email ();
1342 checked_set (_kdm_email, Config::instance()->kdm_email ());
1345 wxTextCtrl* _mail_server;
1346 wxSpinCtrl* _mail_port;
1347 wxTextCtrl* _mail_user;
1348 wxTextCtrl* _mail_password;
1349 wxTextCtrl* _kdm_subject;
1350 wxTextCtrl* _kdm_from;
1351 EditableList<string, EmailDialog>* _kdm_cc;
1352 wxTextCtrl* _kdm_bcc;
1353 wxTextCtrl* _kdm_email;
1354 wxButton* _reset_kdm_email;
1357 /** @class AdvancedPage
1358 * @brief Advanced page of the preferences dialog.
1360 class AdvancedPage : public StockPage
1363 AdvancedPage (wxSize panel_size, int border)
1364 : StockPage (Kind_Advanced, panel_size, border)
1365 , _maximum_j2k_bandwidth (0)
1366 , _allow_any_dcp_frame_rate (0)
1367 , _only_servers_encode (0)
1372 , _log_debug_decode (0)
1373 , _log_debug_encode (0)
1374 , _log_debug_email (0)
1380 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1381 table->AddGrowableCol (1, 1);
1382 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1385 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1386 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1387 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1388 s->Add (_maximum_j2k_bandwidth, 1);
1389 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1393 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1394 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1395 table->AddSpacer (0);
1397 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1398 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1399 table->AddSpacer (0);
1402 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log:"));
1403 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1405 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log"));
1406 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1410 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1411 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1412 t->Add (_log_general, 1, wxEXPAND | wxALL);
1413 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1414 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1415 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1416 t->Add (_log_error, 1, wxEXPAND | wxALL);
1417 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1418 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1419 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1420 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1421 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1422 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1423 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1424 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1425 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1426 table->Add (t, 0, wxALL, 6);
1429 #ifdef DCPOMATIC_WINDOWS
1430 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1431 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1432 table->AddSpacer (0);
1435 _maximum_j2k_bandwidth->SetRange (1, 1000);
1436 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1437 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1438 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1439 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1440 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1441 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1442 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1443 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1444 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1445 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1446 #ifdef DCPOMATIC_WINDOWS
1447 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1451 void config_changed ()
1453 Config* config = Config::instance ();
1455 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1456 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1457 checked_set (_only_servers_encode, config->only_servers_encode ());
1458 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1459 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1460 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1461 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1462 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1463 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1464 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1465 #ifdef DCPOMATIC_WINDOWS
1466 checked_set (_win32_console, config->win32_console());
1470 void maximum_j2k_bandwidth_changed ()
1472 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1475 void allow_any_dcp_frame_rate_changed ()
1477 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1480 void only_servers_encode_changed ()
1482 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1488 if (_log_general->GetValue ()) {
1489 types |= LogEntry::TYPE_GENERAL;
1491 if (_log_warning->GetValue ()) {
1492 types |= LogEntry::TYPE_WARNING;
1494 if (_log_error->GetValue ()) {
1495 types |= LogEntry::TYPE_ERROR;
1497 if (_log_timing->GetValue ()) {
1498 types |= LogEntry::TYPE_TIMING;
1500 if (_log_debug_decode->GetValue ()) {
1501 types |= LogEntry::TYPE_DEBUG_DECODE;
1503 if (_log_debug_encode->GetValue ()) {
1504 types |= LogEntry::TYPE_DEBUG_ENCODE;
1506 if (_log_debug_email->GetValue ()) {
1507 types |= LogEntry::TYPE_DEBUG_EMAIL;
1509 Config::instance()->set_log_types (types);
1512 #ifdef DCPOMATIC_WINDOWS
1513 void win32_console_changed ()
1515 Config::instance()->set_win32_console (_win32_console->GetValue ());
1519 wxSpinCtrl* _maximum_j2k_bandwidth;
1520 wxCheckBox* _allow_any_dcp_frame_rate;
1521 wxCheckBox* _only_servers_encode;
1522 wxCheckBox* _log_general;
1523 wxCheckBox* _log_warning;
1524 wxCheckBox* _log_error;
1525 wxCheckBox* _log_timing;
1526 wxCheckBox* _log_debug_decode;
1527 wxCheckBox* _log_debug_encode;
1528 wxCheckBox* _log_debug_email;
1529 #ifdef DCPOMATIC_WINDOWS
1530 wxCheckBox* _win32_console;
1534 wxPreferencesEditor*
1535 create_config_dialog ()
1537 wxPreferencesEditor* e = new wxPreferencesEditor ();
1539 #ifdef DCPOMATIC_OSX
1540 /* Width that we force some of the config panels to be on OSX so that
1541 the containing window doesn't shrink too much when we select those panels.
1542 This is obviously an unpleasant hack.
1544 wxSize ps = wxSize (520, -1);
1545 int const border = 16;
1547 wxSize ps = wxSize (-1, -1);
1548 int const border = 8;
1551 e->AddPage (new GeneralPage (ps, border));
1552 e->AddPage (new DefaultsPage (ps, border));
1553 e->AddPage (new EncodingServersPage (ps, border));
1554 e->AddPage (new KeysPage (ps, border));
1555 e->AddPage (new TMSPage (ps, border));
1556 e->AddPage (new KDMEmailPage (ps, border));
1557 e->AddPage (new AdvancedPage (ps, border));