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 <wx/stdpaths.h>
47 #include <wx/preferences.h>
48 #include <wx/spinctrl.h>
49 #include <wx/filepicker.h>
50 #include <boost/filesystem.hpp>
51 #include <boost/foreach.hpp>
62 using boost::shared_ptr;
63 using boost::function;
64 using boost::optional;
69 Page (wxSize panel_size, int border)
72 , _panel_size (panel_size)
73 , _window_exists (false)
75 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
81 wxWindow* create_window (wxWindow* parent)
83 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
84 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
88 _window_exists = true;
91 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
100 virtual void config_changed () = 0;
101 virtual void setup () = 0;
103 void config_changed_wrapper ()
105 if (_window_exists) {
110 void window_destroyed ()
112 _window_exists = false;
116 boost::signals2::scoped_connection _config_connection;
120 class StockPage : public wxStockPreferencesPage, public Page
123 StockPage (Kind kind, wxSize panel_size, int border)
124 : wxStockPreferencesPage (kind)
125 , Page (panel_size, border)
128 wxWindow* CreateWindow (wxWindow* parent)
130 return create_window (parent);
134 class StandardPage : public wxPreferencesPage, public Page
137 StandardPage (wxSize panel_size, int border)
138 : Page (panel_size, border)
141 wxWindow* CreateWindow (wxWindow* parent)
143 return create_window (parent);
147 class GeneralPage : public StockPage
150 GeneralPage (wxSize panel_size, int border)
151 : StockPage (Kind_General, panel_size, border)
157 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
158 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
161 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
162 table->Add (_set_language, wxGBPosition (r, 0));
163 _language = new wxChoice (_panel, wxID_ANY);
164 vector<pair<string, string> > languages;
165 languages.push_back (make_pair ("Čeština", "cs_CZ"));
166 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
167 languages.push_back (make_pair ("Dansk", "da_DK"));
168 languages.push_back (make_pair ("Deutsch", "de_DE"));
169 languages.push_back (make_pair ("English", "en_GB"));
170 languages.push_back (make_pair ("Español", "es_ES"));
171 languages.push_back (make_pair ("Français", "fr_FR"));
172 languages.push_back (make_pair ("Italiano", "it_IT"));
173 languages.push_back (make_pair ("Nederlands", "nl_NL"));
174 languages.push_back (make_pair ("Русский", "ru_RU"));
175 languages.push_back (make_pair ("Polski", "pl_PL"));
176 languages.push_back (make_pair ("Português europeu", "pt_PT"));
177 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
178 languages.push_back (make_pair ("Svenska", "sv_SE"));
179 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
180 languages.push_back (make_pair ("українська мова", "uk_UA"));
181 checked_set (_language, languages);
182 table->Add (_language, wxGBPosition (r, 1));
185 wxStaticText* restart = add_label_to_sizer (
186 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
188 wxFont font = restart->GetFont();
189 font.SetStyle (wxFONTSTYLE_ITALIC);
190 font.SetPointSize (font.GetPointSize() - 1);
191 restart->SetFont (font);
194 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
195 _num_local_encoding_threads = new wxSpinCtrl (_panel);
196 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
199 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
200 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
201 table->Add (_cinemas_file, wxGBPosition (r, 1));
204 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
205 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
206 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
210 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
211 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
214 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
215 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
218 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
219 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
222 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
223 bottom_table->AddGrowableCol (1, 1);
225 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
226 _issuer = new wxTextCtrl (_panel, wxID_ANY);
227 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
229 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
230 _creator = new wxTextCtrl (_panel, wxID_ANY);
231 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
233 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
236 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
237 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
238 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
240 _num_local_encoding_threads->SetRange (1, 128);
241 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
243 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
244 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
246 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
247 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
248 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
250 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
251 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::creator_changed, this));
254 void config_changed ()
256 Config* config = Config::instance ();
258 checked_set (_set_language, static_cast<bool>(config->language()));
260 /* Backwards compatibility of config file */
262 map<string, string> compat_map;
263 compat_map["fr"] = "fr_FR";
264 compat_map["it"] = "it_IT";
265 compat_map["es"] = "es_ES";
266 compat_map["sv"] = "sv_SE";
267 compat_map["de"] = "de_DE";
268 compat_map["nl"] = "nl_NL";
269 compat_map["ru"] = "ru_RU";
270 compat_map["pl"] = "pl_PL";
271 compat_map["da"] = "da_DK";
272 compat_map["pt"] = "pt_PT";
273 compat_map["sk"] = "sk_SK";
274 compat_map["cs"] = "cs_CZ";
275 compat_map["uk"] = "uk_UA";
277 string lang = config->language().get_value_or ("en_GB");
278 if (compat_map.find (lang) != compat_map.end ()) {
279 lang = compat_map[lang];
282 checked_set (_language, lang);
284 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
285 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
286 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
288 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
289 checked_set (_check_for_updates, config->check_for_updates ());
290 checked_set (_check_for_test_updates, config->check_for_test_updates ());
291 checked_set (_issuer, config->dcp_issuer ());
292 checked_set (_creator, config->dcp_creator ());
293 checked_set (_cinemas_file, config->cinemas_file());
295 setup_sensitivity ();
298 void setup_sensitivity ()
300 _language->Enable (_set_language->GetValue ());
301 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
304 void set_language_changed ()
306 setup_sensitivity ();
307 if (_set_language->GetValue ()) {
310 Config::instance()->unset_language ();
314 void language_changed ()
316 int const sel = _language->GetSelection ();
318 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
320 Config::instance()->unset_language ();
324 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
325 void analyse_ebur128_changed ()
327 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
331 void automatic_audio_analysis_changed ()
333 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
336 void check_for_updates_changed ()
338 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
341 void check_for_test_updates_changed ()
343 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
346 void num_local_encoding_threads_changed ()
348 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
351 void issuer_changed ()
353 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
356 void creator_changed ()
358 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
361 void cinemas_file_changed ()
363 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
366 wxCheckBox* _set_language;
368 wxSpinCtrl* _num_local_encoding_threads;
369 FilePickerCtrl* _cinemas_file;
370 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
371 wxCheckBox* _analyse_ebur128;
373 wxCheckBox* _automatic_audio_analysis;
374 wxCheckBox* _check_for_updates;
375 wxCheckBox* _check_for_test_updates;
377 wxTextCtrl* _creator;
380 class DefaultsPage : public StandardPage
383 DefaultsPage (wxSize panel_size, int border)
384 : StandardPage (panel_size, border)
387 wxString GetName () const
389 return _("Defaults");
393 wxBitmap GetLargeIcon () const
395 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
402 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
403 table->AddGrowableCol (1, 1);
404 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
407 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
408 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
409 _still_length = new wxSpinCtrl (_panel);
410 s->Add (_still_length);
411 add_label_to_sizer (s, _panel, _("s"), false);
415 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
416 #ifdef DCPOMATIC_USE_OWN_PICKER
417 _directory = new DirPickerCtrl (_panel);
419 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
421 table->Add (_directory, 1, wxEXPAND);
423 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
424 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
425 table->Add (_isdcf_metadata_button);
427 add_label_to_sizer (table, _panel, _("Default container"), true);
428 _container = new wxChoice (_panel, wxID_ANY);
429 table->Add (_container);
431 add_label_to_sizer (table, _panel, _("Default content type"), true);
432 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
433 table->Add (_dcp_content_type);
435 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
436 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
437 table->Add (_dcp_audio_channels);
440 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
441 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
442 _j2k_bandwidth = new wxSpinCtrl (_panel);
443 s->Add (_j2k_bandwidth);
444 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
449 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
450 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
451 _audio_delay = new wxSpinCtrl (_panel);
452 s->Add (_audio_delay);
453 add_label_to_sizer (s, _panel, _("ms"), false);
457 add_label_to_sizer (table, _panel, _("Default standard"), true);
458 _standard = new wxChoice (_panel, wxID_ANY);
459 table->Add (_standard);
461 _still_length->SetRange (1, 3600);
462 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
464 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
466 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
468 vector<Ratio const *> ratios = Ratio::all ();
469 for (size_t i = 0; i < ratios.size(); ++i) {
470 _container->Append (std_to_wx (ratios[i]->nickname ()));
473 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
475 vector<DCPContentType const *> const ct = DCPContentType::all ();
476 for (size_t i = 0; i < ct.size(); ++i) {
477 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
480 vector<pair<string, string> > items;
481 for (int i = 0; i <= 16; i += 2) {
482 items.push_back (make_pair (raw_convert<string> (i), raw_convert<string> (i)));
485 checked_set (_dcp_audio_channels, items);
487 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
488 _dcp_audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
490 _j2k_bandwidth->SetRange (50, 250);
491 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
493 _audio_delay->SetRange (-1000, 1000);
494 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
496 _standard->Append (_("SMPTE"));
497 _standard->Append (_("Interop"));
498 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
501 void config_changed ()
503 Config* config = Config::instance ();
505 vector<Ratio const *> ratios = Ratio::all ();
506 for (size_t i = 0; i < ratios.size(); ++i) {
507 if (ratios[i] == config->default_container ()) {
508 _container->SetSelection (i);
512 vector<DCPContentType const *> const ct = DCPContentType::all ();
513 for (size_t i = 0; i < ct.size(); ++i) {
514 if (ct[i] == config->default_dcp_content_type ()) {
515 _dcp_content_type->SetSelection (i);
519 checked_set (_still_length, config->default_still_length ());
520 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
521 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
522 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
523 checked_set (_dcp_audio_channels, raw_convert<string> (config->default_dcp_audio_channels()));
524 checked_set (_audio_delay, config->default_audio_delay ());
525 checked_set (_standard, config->default_interop() ? 1 : 0);
528 void j2k_bandwidth_changed ()
530 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
533 void audio_delay_changed ()
535 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
538 void dcp_audio_channels_changed ()
540 int const s = _dcp_audio_channels->GetSelection ();
541 if (s != wxNOT_FOUND) {
542 Config::instance()->set_default_dcp_audio_channels (s * 2);
546 void directory_changed ()
548 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
551 void edit_isdcf_metadata_clicked ()
553 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
555 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
559 void still_length_changed ()
561 Config::instance()->set_default_still_length (_still_length->GetValue ());
564 void container_changed ()
566 vector<Ratio const *> ratio = Ratio::all ();
567 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
570 void dcp_content_type_changed ()
572 vector<DCPContentType const *> ct = DCPContentType::all ();
573 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
576 void standard_changed ()
578 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
581 wxSpinCtrl* _j2k_bandwidth;
582 wxSpinCtrl* _audio_delay;
583 wxButton* _isdcf_metadata_button;
584 wxSpinCtrl* _still_length;
585 #ifdef DCPOMATIC_USE_OWN_PICKER
586 DirPickerCtrl* _directory;
588 wxDirPickerCtrl* _directory;
590 wxChoice* _container;
591 wxChoice* _dcp_content_type;
592 wxChoice* _dcp_audio_channels;
596 class EncodingServersPage : public StandardPage
599 EncodingServersPage (wxSize panel_size, int border)
600 : StandardPage (panel_size, border)
603 wxString GetName () const
609 wxBitmap GetLargeIcon () const
611 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
618 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
619 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
621 vector<string> columns;
622 columns.push_back (wx_to_std (_("IP address / host name")));
623 _servers_list = new EditableList<string, ServerDialog> (
626 boost::bind (&Config::servers, Config::instance()),
627 boost::bind (&Config::set_servers, Config::instance(), _1),
628 boost::bind (&always_valid),
629 boost::bind (&EncodingServersPage::server_column, this, _1)
632 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
634 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
637 void config_changed ()
639 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
640 _servers_list->refresh ();
643 void use_any_servers_changed ()
645 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
648 string server_column (string s)
653 wxCheckBox* _use_any_servers;
654 EditableList<string, ServerDialog>* _servers_list;
657 class CertificateChainEditor : public wxPanel
660 CertificateChainEditor (
664 function<void (shared_ptr<dcp::CertificateChain>)> set,
665 function<shared_ptr<const dcp::CertificateChain> (void)> get
671 wxFont subheading_font (*wxNORMAL_FONT);
672 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
674 _sizer = new wxBoxSizer (wxVERTICAL);
677 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
678 m->SetFont (subheading_font);
679 _sizer->Add (m, 0, wxALL, border);
682 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
683 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
685 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
690 ip.SetText (_("Type"));
692 _certificates->InsertColumn (0, ip);
698 ip.SetText (_("Thumbprint"));
701 wxFont font = ip.GetFont ();
702 font.SetFamily (wxFONTFAMILY_TELETYPE);
705 _certificates->InsertColumn (1, ip);
708 certificates_sizer->Add (_certificates, 1, wxEXPAND);
711 wxSizer* s = new wxBoxSizer (wxVERTICAL);
712 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
713 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
714 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
715 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
716 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
717 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
718 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
721 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
722 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
725 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
726 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
727 wxFont font = _private_key->GetFont ();
728 font.SetFamily (wxFONTFAMILY_TELETYPE);
729 _private_key->SetFont (font);
730 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
731 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
732 table->Add (_load_private_key, wxGBPosition (r, 2));
733 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
734 table->Add (_export_private_key, wxGBPosition (r, 3));
737 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
738 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates and key..."));
739 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
740 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
743 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::add_certificate, this));
744 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remove_certificate, this));
745 _export_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_certificate, this));
746 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
747 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
748 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remake_certificates, this));
749 _load_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::load_private_key, this));
750 _export_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_private_key, this));
752 SetSizerAndFit (_sizer);
755 void config_changed ()
757 _chain.reset (new dcp::CertificateChain (*_get().get ()));
759 update_certificate_list ();
760 update_private_key ();
761 update_sensitivity ();
764 void add_button (wxWindow* button)
766 _button_sizer->Add (button);
771 void add_certificate ()
773 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
775 if (d->ShowModal() == wxID_OK) {
777 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
778 if (c.extra_data ()) {
781 _("This file contains other certificates (or other data) after its first certificate. "
782 "Only the first certificate will be used.")
787 update_certificate_list ();
788 } catch (dcp::MiscError& e) {
789 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
795 update_sensitivity ();
798 void remove_certificate ()
800 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
805 _certificates->DeleteItem (i);
809 update_sensitivity ();
812 void export_certificate ()
814 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
819 wxFileDialog* d = new wxFileDialog (
820 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
821 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
824 dcp::CertificateChain::List all = _chain->root_to_leaf ();
825 dcp::CertificateChain::List::iterator j = all.begin ();
826 for (int k = 0; k < i; ++k) {
830 if (d->ShowModal () == wxID_OK) {
831 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
833 throw OpenFileError (wx_to_std (d->GetPath ()));
836 string const s = j->certificate (true);
837 fwrite (s.c_str(), 1, s.length(), f);
843 void update_certificate_list ()
845 _certificates->DeleteAllItems ();
847 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
848 BOOST_FOREACH (dcp::Certificate const & i, certs) {
851 _certificates->InsertItem (item);
852 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
855 _certificates->SetItem (n, 0, _("Root"));
856 } else if (n == (certs.size() - 1)) {
857 _certificates->SetItem (n, 0, _("Leaf"));
859 _certificates->SetItem (n, 0, _("Intermediate"));
866 void remake_certificates ()
868 shared_ptr<const dcp::CertificateChain> chain = _get ();
870 string subject_organization_name;
871 string subject_organizational_unit_name;
872 string root_common_name;
873 string intermediate_common_name;
874 string leaf_common_name;
876 dcp::CertificateChain::List all = chain->root_to_leaf ();
878 if (all.size() >= 1) {
880 subject_organization_name = chain->root().subject_organization_name ();
881 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
882 root_common_name = chain->root().subject_common_name ();
885 if (all.size() >= 2) {
887 leaf_common_name = chain->leaf().subject_common_name ();
890 if (all.size() >= 3) {
891 /* Have an intermediate */
892 dcp::CertificateChain::List::iterator i = all.begin ();
894 intermediate_common_name = i->subject_common_name ();
897 MakeChainDialog* d = new MakeChainDialog (
899 subject_organization_name,
900 subject_organizational_unit_name,
902 intermediate_common_name,
906 if (d->ShowModal () == wxID_OK) {
908 new dcp::CertificateChain (
911 d->organisational_unit (),
912 d->root_common_name (),
913 d->intermediate_common_name (),
914 d->leaf_common_name ()
919 update_certificate_list ();
920 update_private_key ();
926 void update_sensitivity ()
928 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
929 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
932 void update_private_key ()
934 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
938 void load_private_key ()
940 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
942 if (d->ShowModal() == wxID_OK) {
944 boost::filesystem::path p (wx_to_std (d->GetPath ()));
945 if (boost::filesystem::file_size (p) > 8192) {
948 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
953 _chain->set_key (dcp::file_to_string (p));
955 update_private_key ();
956 } catch (dcp::MiscError& e) {
957 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
963 update_sensitivity ();
966 void export_private_key ()
968 optional<string> key = _chain->key ();
973 wxFileDialog* d = new wxFileDialog (
974 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
975 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
978 if (d->ShowModal () == wxID_OK) {
979 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
981 throw OpenFileError (wx_to_std (d->GetPath ()));
984 string const s = _chain->key().get ();
985 fwrite (s.c_str(), 1, s.length(), f);
991 wxListCtrl* _certificates;
992 wxButton* _add_certificate;
993 wxButton* _export_certificate;
994 wxButton* _remove_certificate;
995 wxButton* _remake_certificates;
996 wxStaticText* _private_key;
997 wxButton* _load_private_key;
998 wxButton* _export_private_key;
1000 wxBoxSizer* _button_sizer;
1001 shared_ptr<dcp::CertificateChain> _chain;
1002 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1003 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1006 class KeysPage : public StandardPage
1009 KeysPage (wxSize panel_size, int border)
1010 : StandardPage (panel_size, border)
1013 wxString GetName () const
1018 #ifdef DCPOMATIC_OSX
1019 wxBitmap GetLargeIcon () const
1021 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1029 _signer = new CertificateChainEditor (
1030 _panel, _("Signing DCPs and KDMs"), _border,
1031 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1032 boost::bind (&Config::signer_chain, Config::instance ())
1035 _panel->GetSizer()->Add (_signer);
1037 _decryption = new CertificateChainEditor (
1038 _panel, _("Decrypting DCPs"), _border,
1039 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1040 boost::bind (&Config::decryption_chain, Config::instance ())
1043 _panel->GetSizer()->Add (_decryption);
1045 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption certificate..."));
1046 _decryption->add_button (_export_decryption_certificate);
1048 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1051 void export_decryption_certificate ()
1053 wxFileDialog* d = new wxFileDialog (
1054 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1055 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1058 if (d->ShowModal () == wxID_OK) {
1059 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1061 throw OpenFileError (wx_to_std (d->GetPath ()));
1064 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1065 fwrite (s.c_str(), 1, s.length(), f);
1071 void config_changed ()
1073 _signer->config_changed ();
1074 _decryption->config_changed ();
1077 CertificateChainEditor* _signer;
1078 CertificateChainEditor* _decryption;
1079 wxButton* _export_decryption_certificate;
1082 class TMSPage : public StandardPage
1085 TMSPage (wxSize panel_size, int border)
1086 : StandardPage (panel_size, border)
1089 wxString GetName () const
1094 #ifdef DCPOMATIC_OSX
1095 wxBitmap GetLargeIcon () const
1097 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1104 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1105 table->AddGrowableCol (1, 1);
1106 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1108 add_label_to_sizer (table, _panel, _("Protocol"), true);
1109 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1110 table->Add (_tms_protocol, 1, wxEXPAND);
1112 add_label_to_sizer (table, _panel, _("IP address"), true);
1113 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1114 table->Add (_tms_ip, 1, wxEXPAND);
1116 add_label_to_sizer (table, _panel, _("Target path"), true);
1117 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1118 table->Add (_tms_path, 1, wxEXPAND);
1120 add_label_to_sizer (table, _panel, _("User name"), true);
1121 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1122 table->Add (_tms_user, 1, wxEXPAND);
1124 add_label_to_sizer (table, _panel, _("Password"), true);
1125 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1126 table->Add (_tms_password, 1, wxEXPAND);
1128 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1129 _tms_protocol->Append (_("FTP (for Dolby)"));
1131 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1132 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1133 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1134 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1135 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1138 void config_changed ()
1140 Config* config = Config::instance ();
1142 checked_set (_tms_protocol, config->tms_protocol ());
1143 checked_set (_tms_ip, config->tms_ip ());
1144 checked_set (_tms_path, config->tms_path ());
1145 checked_set (_tms_user, config->tms_user ());
1146 checked_set (_tms_password, config->tms_password ());
1149 void tms_protocol_changed ()
1151 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1154 void tms_ip_changed ()
1156 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1159 void tms_path_changed ()
1161 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1164 void tms_user_changed ()
1166 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1169 void tms_password_changed ()
1171 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1174 wxChoice* _tms_protocol;
1175 wxTextCtrl* _tms_ip;
1176 wxTextCtrl* _tms_path;
1177 wxTextCtrl* _tms_user;
1178 wxTextCtrl* _tms_password;
1187 class KDMEmailPage : public StandardPage
1191 KDMEmailPage (wxSize panel_size, int border)
1192 #ifdef DCPOMATIC_OSX
1193 /* We have to force both width and height of this one */
1194 : StandardPage (wxSize (480, 128), border)
1196 : StandardPage (panel_size, border)
1200 wxString GetName () const
1202 return _("KDM Email");
1205 #ifdef DCPOMATIC_OSX
1206 wxBitmap GetLargeIcon () const
1208 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1215 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1216 table->AddGrowableCol (1, 1);
1217 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1219 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1221 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1222 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1223 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1224 add_label_to_sizer (s, _panel, _("port"), false);
1225 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1226 _mail_port->SetRange (0, 65535);
1227 s->Add (_mail_port);
1228 table->Add (s, 1, wxEXPAND | wxALL);
1231 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1232 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1233 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1235 add_label_to_sizer (table, _panel, _("Mail password"), true);
1236 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1237 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1239 add_label_to_sizer (table, _panel, _("Subject"), true);
1240 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1241 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1243 add_label_to_sizer (table, _panel, _("From address"), true);
1244 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1245 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1247 vector<string> columns;
1248 columns.push_back (wx_to_std (_("Address")));
1249 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1250 _kdm_cc = new EditableList<string, EmailDialog> (
1253 bind (&Config::kdm_cc, Config::instance()),
1254 bind (&Config::set_kdm_cc, Config::instance(), _1),
1255 bind (&string_not_empty, _1),
1258 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1260 add_label_to_sizer (table, _panel, _("BCC address"), true);
1261 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1262 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1264 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1265 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1267 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1268 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1272 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1273 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1274 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1275 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1276 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1277 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1278 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1279 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1280 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1283 void config_changed ()
1285 Config* config = Config::instance ();
1287 checked_set (_mail_server, config->mail_server ());
1288 checked_set (_mail_port, config->mail_port ());
1289 checked_set (_mail_user, config->mail_user ());
1290 checked_set (_mail_password, config->mail_password ());
1291 checked_set (_kdm_subject, config->kdm_subject ());
1292 checked_set (_kdm_from, config->kdm_from ());
1293 checked_set (_kdm_bcc, config->kdm_bcc ());
1294 checked_set (_kdm_email, Config::instance()->kdm_email ());
1297 void mail_server_changed ()
1299 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1302 void mail_port_changed ()
1304 Config::instance()->set_mail_port (_mail_port->GetValue ());
1307 void mail_user_changed ()
1309 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1312 void mail_password_changed ()
1314 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1317 void kdm_subject_changed ()
1319 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1322 void kdm_from_changed ()
1324 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1327 void kdm_bcc_changed ()
1329 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1332 void kdm_email_changed ()
1334 if (_kdm_email->GetValue().IsEmpty ()) {
1335 /* Sometimes we get sent an erroneous notification that the email
1336 is empty; I don't know why.
1340 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1343 void reset_kdm_email ()
1345 Config::instance()->reset_kdm_email ();
1346 checked_set (_kdm_email, Config::instance()->kdm_email ());
1349 wxTextCtrl* _mail_server;
1350 wxSpinCtrl* _mail_port;
1351 wxTextCtrl* _mail_user;
1352 wxTextCtrl* _mail_password;
1353 wxTextCtrl* _kdm_subject;
1354 wxTextCtrl* _kdm_from;
1355 EditableList<string, EmailDialog>* _kdm_cc;
1356 wxTextCtrl* _kdm_bcc;
1357 wxTextCtrl* _kdm_email;
1358 wxButton* _reset_kdm_email;
1361 /** @class AdvancedPage
1362 * @brief Advanced page of the preferences dialog.
1364 class AdvancedPage : public StockPage
1367 AdvancedPage (wxSize panel_size, int border)
1368 : StockPage (Kind_Advanced, panel_size, border)
1369 , _maximum_j2k_bandwidth (0)
1370 , _allow_any_dcp_frame_rate (0)
1371 , _only_servers_encode (0)
1376 , _log_debug_decode (0)
1377 , _log_debug_encode (0)
1378 , _log_debug_email (0)
1384 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1385 table->AddGrowableCol (1, 1);
1386 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1389 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1390 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1391 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1392 s->Add (_maximum_j2k_bandwidth, 1);
1393 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1397 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1398 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1399 table->AddSpacer (0);
1401 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1402 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1403 table->AddSpacer (0);
1406 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log:"));
1407 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1409 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log"));
1410 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1414 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1415 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1416 t->Add (_log_general, 1, wxEXPAND | wxALL);
1417 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1418 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1419 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1420 t->Add (_log_error, 1, wxEXPAND | wxALL);
1421 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1422 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1423 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1424 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1425 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1426 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1427 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1428 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1429 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1430 table->Add (t, 0, wxALL, 6);
1433 #ifdef DCPOMATIC_WINDOWS
1434 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1435 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1436 table->AddSpacer (0);
1439 _maximum_j2k_bandwidth->SetRange (1, 1000);
1440 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1441 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1442 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1443 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1444 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1445 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1446 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1447 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1448 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1449 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1450 #ifdef DCPOMATIC_WINDOWS
1451 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1455 void config_changed ()
1457 Config* config = Config::instance ();
1459 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1460 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1461 checked_set (_only_servers_encode, config->only_servers_encode ());
1462 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1463 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1464 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1465 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1466 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1467 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1468 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1469 #ifdef DCPOMATIC_WINDOWS
1470 checked_set (_win32_console, config->win32_console());
1474 void maximum_j2k_bandwidth_changed ()
1476 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1479 void allow_any_dcp_frame_rate_changed ()
1481 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1484 void only_servers_encode_changed ()
1486 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1492 if (_log_general->GetValue ()) {
1493 types |= LogEntry::TYPE_GENERAL;
1495 if (_log_warning->GetValue ()) {
1496 types |= LogEntry::TYPE_WARNING;
1498 if (_log_error->GetValue ()) {
1499 types |= LogEntry::TYPE_ERROR;
1501 if (_log_timing->GetValue ()) {
1502 types |= LogEntry::TYPE_TIMING;
1504 if (_log_debug_decode->GetValue ()) {
1505 types |= LogEntry::TYPE_DEBUG_DECODE;
1507 if (_log_debug_encode->GetValue ()) {
1508 types |= LogEntry::TYPE_DEBUG_ENCODE;
1510 if (_log_debug_email->GetValue ()) {
1511 types |= LogEntry::TYPE_DEBUG_EMAIL;
1513 Config::instance()->set_log_types (types);
1516 #ifdef DCPOMATIC_WINDOWS
1517 void win32_console_changed ()
1519 Config::instance()->set_win32_console (_win32_console->GetValue ());
1523 wxSpinCtrl* _maximum_j2k_bandwidth;
1524 wxCheckBox* _allow_any_dcp_frame_rate;
1525 wxCheckBox* _only_servers_encode;
1526 wxCheckBox* _log_general;
1527 wxCheckBox* _log_warning;
1528 wxCheckBox* _log_error;
1529 wxCheckBox* _log_timing;
1530 wxCheckBox* _log_debug_decode;
1531 wxCheckBox* _log_debug_encode;
1532 wxCheckBox* _log_debug_email;
1533 #ifdef DCPOMATIC_WINDOWS
1534 wxCheckBox* _win32_console;
1538 wxPreferencesEditor*
1539 create_config_dialog ()
1541 wxPreferencesEditor* e = new wxPreferencesEditor ();
1543 #ifdef DCPOMATIC_OSX
1544 /* Width that we force some of the config panels to be on OSX so that
1545 the containing window doesn't shrink too much when we select those panels.
1546 This is obviously an unpleasant hack.
1548 wxSize ps = wxSize (520, -1);
1549 int const border = 16;
1551 wxSize ps = wxSize (-1, -1);
1552 int const border = 8;
1555 e->AddPage (new GeneralPage (ps, border));
1556 e->AddPage (new DefaultsPage (ps, border));
1557 e->AddPage (new EncodingServersPage (ps, border));
1558 e->AddPage (new KeysPage (ps, border));
1559 e->AddPage (new TMSPage (ps, border));
1560 e->AddPage (new KDMEmailPage (ps, border));
1561 e->AddPage (new AdvancedPage (ps, border));