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 "name_format_editor.h"
36 #include "lib/config.h"
37 #include "lib/ratio.h"
38 #include "lib/filter.h"
39 #include "lib/dcp_content_type.h"
42 #include "lib/raw_convert.h"
43 #include "lib/cross.h"
44 #include "lib/exceptions.h"
45 #include <dcp/exceptions.h>
46 #include <dcp/certificate_chain.h>
47 #include <dcp/raw_convert.h>
48 #include <wx/stdpaths.h>
49 #include <wx/preferences.h>
50 #include <wx/spinctrl.h>
51 #include <wx/filepicker.h>
52 #include <boost/filesystem.hpp>
53 #include <boost/foreach.hpp>
64 using boost::shared_ptr;
65 using boost::function;
66 using boost::optional;
71 Page (wxSize panel_size, int border)
74 , _panel_size (panel_size)
75 , _window_exists (false)
77 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
83 wxWindow* create_window (wxWindow* parent)
85 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
86 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
90 _window_exists = true;
93 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
102 virtual void config_changed () = 0;
103 virtual void setup () = 0;
105 void config_changed_wrapper ()
107 if (_window_exists) {
112 void window_destroyed ()
114 _window_exists = false;
118 boost::signals2::scoped_connection _config_connection;
122 class StockPage : public wxStockPreferencesPage, public Page
125 StockPage (Kind kind, wxSize panel_size, int border)
126 : wxStockPreferencesPage (kind)
127 , Page (panel_size, border)
130 wxWindow* CreateWindow (wxWindow* parent)
132 return create_window (parent);
136 class StandardPage : public wxPreferencesPage, public Page
139 StandardPage (wxSize panel_size, int border)
140 : Page (panel_size, border)
143 wxWindow* CreateWindow (wxWindow* parent)
145 return create_window (parent);
149 class GeneralPage : public StockPage
152 GeneralPage (wxSize panel_size, int border)
153 : StockPage (Kind_General, panel_size, border)
159 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
160 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
163 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
164 table->Add (_set_language, wxGBPosition (r, 0));
165 _language = new wxChoice (_panel, wxID_ANY);
166 vector<pair<string, string> > languages;
167 languages.push_back (make_pair ("Čeština", "cs_CZ"));
168 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
169 languages.push_back (make_pair ("Dansk", "da_DK"));
170 languages.push_back (make_pair ("Deutsch", "de_DE"));
171 languages.push_back (make_pair ("English", "en_GB"));
172 languages.push_back (make_pair ("Español", "es_ES"));
173 languages.push_back (make_pair ("Français", "fr_FR"));
174 languages.push_back (make_pair ("Italiano", "it_IT"));
175 languages.push_back (make_pair ("Nederlands", "nl_NL"));
176 languages.push_back (make_pair ("Русский", "ru_RU"));
177 languages.push_back (make_pair ("Polski", "pl_PL"));
178 languages.push_back (make_pair ("Português europeu", "pt_PT"));
179 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
180 languages.push_back (make_pair ("Svenska", "sv_SE"));
181 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
182 languages.push_back (make_pair ("українська мова", "uk_UA"));
183 checked_set (_language, languages);
184 table->Add (_language, wxGBPosition (r, 1));
187 wxStaticText* restart = add_label_to_sizer (
188 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
190 wxFont font = restart->GetFont();
191 font.SetStyle (wxFONTSTYLE_ITALIC);
192 font.SetPointSize (font.GetPointSize() - 1);
193 restart->SetFont (font);
196 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
197 _num_local_encoding_threads = new wxSpinCtrl (_panel);
198 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
201 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
202 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
203 table->Add (_cinemas_file, wxGBPosition (r, 1));
206 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
207 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
208 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
212 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
213 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
216 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
217 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
220 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
221 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
224 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
225 bottom_table->AddGrowableCol (1, 1);
227 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
228 _issuer = new wxTextCtrl (_panel, wxID_ANY);
229 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
231 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
232 _creator = new wxTextCtrl (_panel, wxID_ANY);
233 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
235 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
238 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
239 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
240 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
242 _num_local_encoding_threads->SetRange (1, 128);
243 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
245 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
246 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
248 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
249 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
250 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
252 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
253 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::creator_changed, this));
256 void config_changed ()
258 Config* config = Config::instance ();
260 checked_set (_set_language, static_cast<bool>(config->language()));
262 /* Backwards compatibility of config file */
264 map<string, string> compat_map;
265 compat_map["fr"] = "fr_FR";
266 compat_map["it"] = "it_IT";
267 compat_map["es"] = "es_ES";
268 compat_map["sv"] = "sv_SE";
269 compat_map["de"] = "de_DE";
270 compat_map["nl"] = "nl_NL";
271 compat_map["ru"] = "ru_RU";
272 compat_map["pl"] = "pl_PL";
273 compat_map["da"] = "da_DK";
274 compat_map["pt"] = "pt_PT";
275 compat_map["sk"] = "sk_SK";
276 compat_map["cs"] = "cs_CZ";
277 compat_map["uk"] = "uk_UA";
279 string lang = config->language().get_value_or ("en_GB");
280 if (compat_map.find (lang) != compat_map.end ()) {
281 lang = compat_map[lang];
284 checked_set (_language, lang);
286 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
287 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
288 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
290 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
291 checked_set (_check_for_updates, config->check_for_updates ());
292 checked_set (_check_for_test_updates, config->check_for_test_updates ());
293 checked_set (_issuer, config->dcp_issuer ());
294 checked_set (_creator, config->dcp_creator ());
295 checked_set (_cinemas_file, config->cinemas_file());
297 setup_sensitivity ();
300 void setup_sensitivity ()
302 _language->Enable (_set_language->GetValue ());
303 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
306 void set_language_changed ()
308 setup_sensitivity ();
309 if (_set_language->GetValue ()) {
312 Config::instance()->unset_language ();
316 void language_changed ()
318 int const sel = _language->GetSelection ();
320 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
322 Config::instance()->unset_language ();
326 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
327 void analyse_ebur128_changed ()
329 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
333 void automatic_audio_analysis_changed ()
335 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
338 void check_for_updates_changed ()
340 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
343 void check_for_test_updates_changed ()
345 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
348 void num_local_encoding_threads_changed ()
350 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
353 void issuer_changed ()
355 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
358 void creator_changed ()
360 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
363 void cinemas_file_changed ()
365 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
368 wxCheckBox* _set_language;
370 wxSpinCtrl* _num_local_encoding_threads;
371 FilePickerCtrl* _cinemas_file;
372 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
373 wxCheckBox* _analyse_ebur128;
375 wxCheckBox* _automatic_audio_analysis;
376 wxCheckBox* _check_for_updates;
377 wxCheckBox* _check_for_test_updates;
379 wxTextCtrl* _creator;
382 class DefaultsPage : public StandardPage
385 DefaultsPage (wxSize panel_size, int border)
386 : StandardPage (panel_size, border)
389 wxString GetName () const
391 return _("Defaults");
395 wxBitmap GetLargeIcon () const
397 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
404 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
405 table->AddGrowableCol (1, 1);
406 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
409 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
410 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
411 _still_length = new wxSpinCtrl (_panel);
412 s->Add (_still_length);
413 add_label_to_sizer (s, _panel, _("s"), false);
417 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
418 #ifdef DCPOMATIC_USE_OWN_PICKER
419 _directory = new DirPickerCtrl (_panel);
421 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
423 table->Add (_directory, 1, wxEXPAND);
425 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
426 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
427 table->Add (_isdcf_metadata_button);
429 add_label_to_sizer (table, _panel, _("Default container"), true);
430 _container = new wxChoice (_panel, wxID_ANY);
431 table->Add (_container);
433 add_label_to_sizer (table, _panel, _("Default content type"), true);
434 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
435 table->Add (_dcp_content_type);
437 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true);
438 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
439 table->Add (_dcp_audio_channels);
442 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
443 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
444 _j2k_bandwidth = new wxSpinCtrl (_panel);
445 s->Add (_j2k_bandwidth);
446 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
451 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
452 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
453 _audio_delay = new wxSpinCtrl (_panel);
454 s->Add (_audio_delay);
455 add_label_to_sizer (s, _panel, _("ms"), false);
459 add_label_to_sizer (table, _panel, _("Default standard"), true);
460 _standard = new wxChoice (_panel, wxID_ANY);
461 table->Add (_standard);
463 _still_length->SetRange (1, 3600);
464 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
466 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
468 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
470 vector<Ratio const *> ratios = Ratio::all ();
471 for (size_t i = 0; i < ratios.size(); ++i) {
472 _container->Append (std_to_wx (ratios[i]->nickname ()));
475 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
477 vector<DCPContentType const *> const ct = DCPContentType::all ();
478 for (size_t i = 0; i < ct.size(); ++i) {
479 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
482 setup_audio_channels_choice (_dcp_audio_channels, 2);
484 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
485 _dcp_audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
487 _j2k_bandwidth->SetRange (50, 250);
488 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
490 _audio_delay->SetRange (-1000, 1000);
491 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
493 _standard->Append (_("SMPTE"));
494 _standard->Append (_("Interop"));
495 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
498 void config_changed ()
500 Config* config = Config::instance ();
502 vector<Ratio const *> ratios = Ratio::all ();
503 for (size_t i = 0; i < ratios.size(); ++i) {
504 if (ratios[i] == config->default_container ()) {
505 _container->SetSelection (i);
509 vector<DCPContentType const *> const ct = DCPContentType::all ();
510 for (size_t i = 0; i < ct.size(); ++i) {
511 if (ct[i] == config->default_dcp_content_type ()) {
512 _dcp_content_type->SetSelection (i);
516 checked_set (_still_length, config->default_still_length ());
517 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
518 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
519 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
520 checked_set (_dcp_audio_channels, raw_convert<string> (config->default_dcp_audio_channels()));
521 checked_set (_audio_delay, config->default_audio_delay ());
522 checked_set (_standard, config->default_interop() ? 1 : 0);
525 void j2k_bandwidth_changed ()
527 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
530 void audio_delay_changed ()
532 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
535 void dcp_audio_channels_changed ()
537 int const s = _dcp_audio_channels->GetSelection ();
538 if (s != wxNOT_FOUND) {
539 Config::instance()->set_default_dcp_audio_channels (dcp::raw_convert<int> (string_client_data (_dcp_audio_channels->GetClientObject (s))));
543 void directory_changed ()
545 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
548 void edit_isdcf_metadata_clicked ()
550 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
552 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
556 void still_length_changed ()
558 Config::instance()->set_default_still_length (_still_length->GetValue ());
561 void container_changed ()
563 vector<Ratio const *> ratio = Ratio::all ();
564 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
567 void dcp_content_type_changed ()
569 vector<DCPContentType const *> ct = DCPContentType::all ();
570 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
573 void standard_changed ()
575 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
578 wxSpinCtrl* _j2k_bandwidth;
579 wxSpinCtrl* _audio_delay;
580 wxButton* _isdcf_metadata_button;
581 wxSpinCtrl* _still_length;
582 #ifdef DCPOMATIC_USE_OWN_PICKER
583 DirPickerCtrl* _directory;
585 wxDirPickerCtrl* _directory;
587 wxChoice* _container;
588 wxChoice* _dcp_content_type;
589 wxChoice* _dcp_audio_channels;
593 class EncodingServersPage : public StandardPage
596 EncodingServersPage (wxSize panel_size, int border)
597 : StandardPage (panel_size, border)
600 wxString GetName () const
606 wxBitmap GetLargeIcon () const
608 return wxBitmap ("servers", wxBITMAP_TYPE_PNG_RESOURCE);
615 _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
616 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
618 vector<string> columns;
619 columns.push_back (wx_to_std (_("IP address / host name")));
620 _servers_list = new EditableList<string, ServerDialog> (
623 boost::bind (&Config::servers, Config::instance()),
624 boost::bind (&Config::set_servers, Config::instance(), _1),
625 boost::bind (&always_valid),
626 boost::bind (&EncodingServersPage::server_column, this, _1)
629 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
631 _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
634 void config_changed ()
636 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
637 _servers_list->refresh ();
640 void use_any_servers_changed ()
642 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
645 string server_column (string s)
650 wxCheckBox* _use_any_servers;
651 EditableList<string, ServerDialog>* _servers_list;
654 class CertificateChainEditor : public wxPanel
657 CertificateChainEditor (
661 function<void (shared_ptr<dcp::CertificateChain>)> set,
662 function<shared_ptr<const dcp::CertificateChain> (void)> get
668 wxFont subheading_font (*wxNORMAL_FONT);
669 subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
671 _sizer = new wxBoxSizer (wxVERTICAL);
674 wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
675 m->SetFont (subheading_font);
676 _sizer->Add (m, 0, wxALL, border);
679 wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
680 _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
682 _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
687 ip.SetText (_("Type"));
689 _certificates->InsertColumn (0, ip);
695 ip.SetText (_("Thumbprint"));
698 wxFont font = ip.GetFont ();
699 font.SetFamily (wxFONTFAMILY_TELETYPE);
702 _certificates->InsertColumn (1, ip);
705 certificates_sizer->Add (_certificates, 1, wxEXPAND);
708 wxSizer* s = new wxBoxSizer (wxVERTICAL);
709 _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
710 s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
711 _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
712 s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
713 _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
714 s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
715 certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
718 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
719 _sizer->Add (table, 1, wxALL | wxEXPAND, border);
722 add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
723 _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
724 wxFont font = _private_key->GetFont ();
725 font.SetFamily (wxFONTFAMILY_TELETYPE);
726 _private_key->SetFont (font);
727 table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
728 _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
729 table->Add (_load_private_key, wxGBPosition (r, 2));
730 _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
731 table->Add (_export_private_key, wxGBPosition (r, 3));
734 _button_sizer = new wxBoxSizer (wxHORIZONTAL);
735 _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates and key..."));
736 _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
737 table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
740 _add_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::add_certificate, this));
741 _remove_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remove_certificate, this));
742 _export_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_certificate, this));
743 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
744 _certificates->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
745 _remake_certificates->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::remake_certificates, this));
746 _load_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::load_private_key, this));
747 _export_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&CertificateChainEditor::export_private_key, this));
749 SetSizerAndFit (_sizer);
752 void config_changed ()
754 _chain.reset (new dcp::CertificateChain (*_get().get ()));
756 update_certificate_list ();
757 update_private_key ();
758 update_sensitivity ();
761 void add_button (wxWindow* button)
763 _button_sizer->Add (button);
768 void add_certificate ()
770 wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
772 if (d->ShowModal() == wxID_OK) {
774 dcp::Certificate c (dcp::file_to_string (wx_to_std (d->GetPath ())));
775 if (c.extra_data ()) {
778 _("This file contains other certificates (or other data) after its first certificate. "
779 "Only the first certificate will be used.")
784 update_certificate_list ();
785 } catch (dcp::MiscError& e) {
786 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
792 update_sensitivity ();
795 void remove_certificate ()
797 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
802 _certificates->DeleteItem (i);
806 update_sensitivity ();
809 void export_certificate ()
811 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
816 wxFileDialog* d = new wxFileDialog (
817 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
818 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
821 dcp::CertificateChain::List all = _chain->root_to_leaf ();
822 dcp::CertificateChain::List::iterator j = all.begin ();
823 for (int k = 0; k < i; ++k) {
827 if (d->ShowModal () == wxID_OK) {
828 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
830 throw OpenFileError (wx_to_std (d->GetPath ()));
833 string const s = j->certificate (true);
834 fwrite (s.c_str(), 1, s.length(), f);
840 void update_certificate_list ()
842 _certificates->DeleteAllItems ();
844 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
845 BOOST_FOREACH (dcp::Certificate const & i, certs) {
848 _certificates->InsertItem (item);
849 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
852 _certificates->SetItem (n, 0, _("Root"));
853 } else if (n == (certs.size() - 1)) {
854 _certificates->SetItem (n, 0, _("Leaf"));
856 _certificates->SetItem (n, 0, _("Intermediate"));
863 void remake_certificates ()
865 shared_ptr<const dcp::CertificateChain> chain = _get ();
867 string subject_organization_name;
868 string subject_organizational_unit_name;
869 string root_common_name;
870 string intermediate_common_name;
871 string leaf_common_name;
873 dcp::CertificateChain::List all = chain->root_to_leaf ();
875 if (all.size() >= 1) {
877 subject_organization_name = chain->root().subject_organization_name ();
878 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
879 root_common_name = chain->root().subject_common_name ();
882 if (all.size() >= 2) {
884 leaf_common_name = chain->leaf().subject_common_name ();
887 if (all.size() >= 3) {
888 /* Have an intermediate */
889 dcp::CertificateChain::List::iterator i = all.begin ();
891 intermediate_common_name = i->subject_common_name ();
894 MakeChainDialog* d = new MakeChainDialog (
896 subject_organization_name,
897 subject_organizational_unit_name,
899 intermediate_common_name,
903 if (d->ShowModal () == wxID_OK) {
905 new dcp::CertificateChain (
908 d->organisational_unit (),
909 d->root_common_name (),
910 d->intermediate_common_name (),
911 d->leaf_common_name ()
916 update_certificate_list ();
917 update_private_key ();
923 void update_sensitivity ()
925 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
926 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
929 void update_private_key ()
931 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
935 void load_private_key ()
937 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
939 if (d->ShowModal() == wxID_OK) {
941 boost::filesystem::path p (wx_to_std (d->GetPath ()));
942 if (boost::filesystem::file_size (p) > 8192) {
945 wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
950 _chain->set_key (dcp::file_to_string (p));
952 update_private_key ();
953 } catch (dcp::MiscError& e) {
954 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
960 update_sensitivity ();
963 void export_private_key ()
965 optional<string> key = _chain->key ();
970 wxFileDialog* d = new wxFileDialog (
971 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
972 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
975 if (d->ShowModal () == wxID_OK) {
976 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
978 throw OpenFileError (wx_to_std (d->GetPath ()));
981 string const s = _chain->key().get ();
982 fwrite (s.c_str(), 1, s.length(), f);
988 wxListCtrl* _certificates;
989 wxButton* _add_certificate;
990 wxButton* _export_certificate;
991 wxButton* _remove_certificate;
992 wxButton* _remake_certificates;
993 wxStaticText* _private_key;
994 wxButton* _load_private_key;
995 wxButton* _export_private_key;
997 wxBoxSizer* _button_sizer;
998 shared_ptr<dcp::CertificateChain> _chain;
999 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
1000 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
1003 class KeysPage : public StandardPage
1006 KeysPage (wxSize panel_size, int border)
1007 : StandardPage (panel_size, border)
1010 wxString GetName () const
1015 #ifdef DCPOMATIC_OSX
1016 wxBitmap GetLargeIcon () const
1018 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1026 _signer = new CertificateChainEditor (
1027 _panel, _("Signing DCPs and KDMs"), _border,
1028 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1029 boost::bind (&Config::signer_chain, Config::instance ())
1032 _panel->GetSizer()->Add (_signer);
1034 _decryption = new CertificateChainEditor (
1035 _panel, _("Decrypting DCPs"), _border,
1036 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1037 boost::bind (&Config::decryption_chain, Config::instance ())
1040 _panel->GetSizer()->Add (_decryption);
1042 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption certificate..."));
1043 _decryption->add_button (_export_decryption_certificate);
1045 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1048 void export_decryption_certificate ()
1050 wxFileDialog* d = new wxFileDialog (
1051 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1052 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1055 if (d->ShowModal () == wxID_OK) {
1056 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1058 throw OpenFileError (wx_to_std (d->GetPath ()));
1061 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1062 fwrite (s.c_str(), 1, s.length(), f);
1068 void config_changed ()
1070 _signer->config_changed ();
1071 _decryption->config_changed ();
1074 CertificateChainEditor* _signer;
1075 CertificateChainEditor* _decryption;
1076 wxButton* _export_decryption_certificate;
1079 class TMSPage : public StandardPage
1082 TMSPage (wxSize panel_size, int border)
1083 : StandardPage (panel_size, border)
1086 wxString GetName () const
1091 #ifdef DCPOMATIC_OSX
1092 wxBitmap GetLargeIcon () const
1094 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1101 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1102 table->AddGrowableCol (1, 1);
1103 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1105 add_label_to_sizer (table, _panel, _("Protocol"), true);
1106 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1107 table->Add (_tms_protocol, 1, wxEXPAND);
1109 add_label_to_sizer (table, _panel, _("IP address"), true);
1110 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1111 table->Add (_tms_ip, 1, wxEXPAND);
1113 add_label_to_sizer (table, _panel, _("Target path"), true);
1114 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1115 table->Add (_tms_path, 1, wxEXPAND);
1117 add_label_to_sizer (table, _panel, _("User name"), true);
1118 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1119 table->Add (_tms_user, 1, wxEXPAND);
1121 add_label_to_sizer (table, _panel, _("Password"), true);
1122 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1123 table->Add (_tms_password, 1, wxEXPAND);
1125 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1126 _tms_protocol->Append (_("FTP (for Dolby)"));
1128 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1129 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1130 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1131 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1132 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1135 void config_changed ()
1137 Config* config = Config::instance ();
1139 checked_set (_tms_protocol, config->tms_protocol ());
1140 checked_set (_tms_ip, config->tms_ip ());
1141 checked_set (_tms_path, config->tms_path ());
1142 checked_set (_tms_user, config->tms_user ());
1143 checked_set (_tms_password, config->tms_password ());
1146 void tms_protocol_changed ()
1148 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1151 void tms_ip_changed ()
1153 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1156 void tms_path_changed ()
1158 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1161 void tms_user_changed ()
1163 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1166 void tms_password_changed ()
1168 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1171 wxChoice* _tms_protocol;
1172 wxTextCtrl* _tms_ip;
1173 wxTextCtrl* _tms_path;
1174 wxTextCtrl* _tms_user;
1175 wxTextCtrl* _tms_password;
1184 class KDMEmailPage : public StandardPage
1188 KDMEmailPage (wxSize panel_size, int border)
1189 #ifdef DCPOMATIC_OSX
1190 /* We have to force both width and height of this one */
1191 : StandardPage (wxSize (480, 128), border)
1193 : StandardPage (panel_size, border)
1197 wxString GetName () const
1199 return _("KDM Email");
1202 #ifdef DCPOMATIC_OSX
1203 wxBitmap GetLargeIcon () const
1205 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1212 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1213 table->AddGrowableCol (1, 1);
1214 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1216 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1218 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1219 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1220 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1221 add_label_to_sizer (s, _panel, _("port"), false);
1222 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1223 _mail_port->SetRange (0, 65535);
1224 s->Add (_mail_port);
1225 table->Add (s, 1, wxEXPAND | wxALL);
1228 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1229 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1230 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1232 add_label_to_sizer (table, _panel, _("Mail password"), true);
1233 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1234 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1236 add_label_to_sizer (table, _panel, _("Subject"), true);
1237 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1238 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1240 add_label_to_sizer (table, _panel, _("From address"), true);
1241 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1242 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1244 vector<string> columns;
1245 columns.push_back (wx_to_std (_("Address")));
1246 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1247 _kdm_cc = new EditableList<string, EmailDialog> (
1250 bind (&Config::kdm_cc, Config::instance()),
1251 bind (&Config::set_kdm_cc, Config::instance(), _1),
1252 bind (&string_not_empty, _1),
1255 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1257 add_label_to_sizer (table, _panel, _("BCC address"), true);
1258 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1259 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1261 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1262 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1264 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1265 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1269 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1270 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1271 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1272 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1273 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1274 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1275 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1276 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1277 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1280 void config_changed ()
1282 Config* config = Config::instance ();
1284 checked_set (_mail_server, config->mail_server ());
1285 checked_set (_mail_port, config->mail_port ());
1286 checked_set (_mail_user, config->mail_user ());
1287 checked_set (_mail_password, config->mail_password ());
1288 checked_set (_kdm_subject, config->kdm_subject ());
1289 checked_set (_kdm_from, config->kdm_from ());
1290 checked_set (_kdm_bcc, config->kdm_bcc ());
1291 checked_set (_kdm_email, Config::instance()->kdm_email ());
1294 void mail_server_changed ()
1296 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1299 void mail_port_changed ()
1301 Config::instance()->set_mail_port (_mail_port->GetValue ());
1304 void mail_user_changed ()
1306 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1309 void mail_password_changed ()
1311 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1314 void kdm_subject_changed ()
1316 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1319 void kdm_from_changed ()
1321 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1324 void kdm_bcc_changed ()
1326 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1329 void kdm_email_changed ()
1331 if (_kdm_email->GetValue().IsEmpty ()) {
1332 /* Sometimes we get sent an erroneous notification that the email
1333 is empty; I don't know why.
1337 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1340 void reset_kdm_email ()
1342 Config::instance()->reset_kdm_email ();
1343 checked_set (_kdm_email, Config::instance()->kdm_email ());
1346 wxTextCtrl* _mail_server;
1347 wxSpinCtrl* _mail_port;
1348 wxTextCtrl* _mail_user;
1349 wxTextCtrl* _mail_password;
1350 wxTextCtrl* _kdm_subject;
1351 wxTextCtrl* _kdm_from;
1352 EditableList<string, EmailDialog>* _kdm_cc;
1353 wxTextCtrl* _kdm_bcc;
1354 wxTextCtrl* _kdm_email;
1355 wxButton* _reset_kdm_email;
1358 /** @class AdvancedPage
1359 * @brief Advanced page of the preferences dialog.
1361 class AdvancedPage : public StockPage
1364 AdvancedPage (wxSize panel_size, int border)
1365 : StockPage (Kind_Advanced, panel_size, border)
1366 , _maximum_j2k_bandwidth (0)
1367 , _allow_any_dcp_frame_rate (0)
1368 , _only_servers_encode (0)
1373 , _log_debug_decode (0)
1374 , _log_debug_encode (0)
1375 , _log_debug_email (0)
1381 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1382 table->AddGrowableCol (1, 1);
1383 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1386 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1387 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1388 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1389 s->Add (_maximum_j2k_bandwidth, 1);
1390 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1394 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1395 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1396 table->AddSpacer (0);
1398 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1399 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1400 table->AddSpacer (0);
1403 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1404 wxString t = _("DCP filename format");
1406 flags |= wxALIGN_RIGHT;
1409 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, t);
1410 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1413 dcp::NameFormat::Map titles;
1414 titles['t'] = "type (j2c/pcm/sub/cpl/pkl)";
1415 titles['i'] = "unique ID";
1416 titles['r'] = "reel number";
1417 titles['n'] = "number of reels";
1418 dcp::NameFormat::Map examples;
1419 examples['t'] = "j2c";
1420 examples['i'] = "eb1c112c-ca3c-4ae6-9263-c6714ff05d64";
1421 examples['r'] = "1";
1422 examples['n'] = "4";
1423 _dcp_filename_format = new NameFormatEditor (_panel, Config::instance()->dcp_filename_format(), titles, examples);
1424 table->Add (_dcp_filename_format->panel(), 1, wxEXPAND | wxALL);
1427 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log:"));
1428 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1430 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log"));
1431 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1435 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1436 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1437 t->Add (_log_general, 1, wxEXPAND | wxALL);
1438 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1439 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1440 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1441 t->Add (_log_error, 1, wxEXPAND | wxALL);
1442 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1443 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1444 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1445 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1446 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1447 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1448 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1449 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1450 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1451 table->Add (t, 0, wxALL, 6);
1454 #ifdef DCPOMATIC_WINDOWS
1455 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1456 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1457 table->AddSpacer (0);
1460 _maximum_j2k_bandwidth->SetRange (1, 1000);
1461 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1462 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1463 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1464 _dcp_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_filename_format_changed, this));
1465 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1466 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1467 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1468 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1469 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1470 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1471 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1472 #ifdef DCPOMATIC_WINDOWS
1473 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1477 void config_changed ()
1479 Config* config = Config::instance ();
1481 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1482 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1483 checked_set (_only_servers_encode, config->only_servers_encode ());
1484 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1485 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1486 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1487 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1488 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1489 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1490 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1491 #ifdef DCPOMATIC_WINDOWS
1492 checked_set (_win32_console, config->win32_console());
1496 void maximum_j2k_bandwidth_changed ()
1498 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1501 void allow_any_dcp_frame_rate_changed ()
1503 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1506 void only_servers_encode_changed ()
1508 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1511 void dcp_filename_format_changed ()
1513 Config::instance()->set_dcp_filename_format (_dcp_filename_format->get ());
1519 if (_log_general->GetValue ()) {
1520 types |= LogEntry::TYPE_GENERAL;
1522 if (_log_warning->GetValue ()) {
1523 types |= LogEntry::TYPE_WARNING;
1525 if (_log_error->GetValue ()) {
1526 types |= LogEntry::TYPE_ERROR;
1528 if (_log_timing->GetValue ()) {
1529 types |= LogEntry::TYPE_TIMING;
1531 if (_log_debug_decode->GetValue ()) {
1532 types |= LogEntry::TYPE_DEBUG_DECODE;
1534 if (_log_debug_encode->GetValue ()) {
1535 types |= LogEntry::TYPE_DEBUG_ENCODE;
1537 if (_log_debug_email->GetValue ()) {
1538 types |= LogEntry::TYPE_DEBUG_EMAIL;
1540 Config::instance()->set_log_types (types);
1543 #ifdef DCPOMATIC_WINDOWS
1544 void win32_console_changed ()
1546 Config::instance()->set_win32_console (_win32_console->GetValue ());
1550 wxSpinCtrl* _maximum_j2k_bandwidth;
1551 wxCheckBox* _allow_any_dcp_frame_rate;
1552 wxCheckBox* _only_servers_encode;
1553 NameFormatEditor* _dcp_filename_format;
1554 wxCheckBox* _log_general;
1555 wxCheckBox* _log_warning;
1556 wxCheckBox* _log_error;
1557 wxCheckBox* _log_timing;
1558 wxCheckBox* _log_debug_decode;
1559 wxCheckBox* _log_debug_encode;
1560 wxCheckBox* _log_debug_email;
1561 #ifdef DCPOMATIC_WINDOWS
1562 wxCheckBox* _win32_console;
1566 wxPreferencesEditor*
1567 create_config_dialog ()
1569 wxPreferencesEditor* e = new wxPreferencesEditor ();
1571 #ifdef DCPOMATIC_OSX
1572 /* Width that we force some of the config panels to be on OSX so that
1573 the containing window doesn't shrink too much when we select those panels.
1574 This is obviously an unpleasant hack.
1576 wxSize ps = wxSize (520, -1);
1577 int const border = 16;
1579 wxSize ps = wxSize (-1, -1);
1580 int const border = 8;
1583 e->AddPage (new GeneralPage (ps, border));
1584 e->AddPage (new DefaultsPage (ps, border));
1585 e->AddPage (new EncodingServersPage (ps, border));
1586 e->AddPage (new KeysPage (ps, border));
1587 e->AddPage (new TMSPage (ps, border));
1588 e->AddPage (new KDMEmailPage (ps, border));
1589 e->AddPage (new AdvancedPage (ps, border));