2 Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /** @file src/config_dialog.cc
21 * @brief A dialogue to edit DCP-o-matic configuration.
24 #include "config_dialog.h"
26 #include "editable_list.h"
27 #include "filter_dialog.h"
28 #include "dir_picker_ctrl.h"
29 #include "file_picker_ctrl.h"
30 #include "isdcf_metadata_dialog.h"
31 #include "server_dialog.h"
32 #include "make_chain_dialog.h"
33 #include "email_dialog.h"
34 #include "lib/config.h"
35 #include "lib/ratio.h"
36 #include "lib/filter.h"
37 #include "lib/dcp_content_type.h"
40 #include "lib/raw_convert.h"
41 #include "lib/cross.h"
42 #include "lib/exceptions.h"
43 #include <dcp/exceptions.h>
44 #include <dcp/certificate_chain.h>
45 #include <wx/stdpaths.h>
46 #include <wx/preferences.h>
47 #include <wx/spinctrl.h>
48 #include <wx/filepicker.h>
49 #include <boost/filesystem.hpp>
50 #include <boost/foreach.hpp>
61 using boost::shared_ptr;
62 using boost::function;
63 using boost::optional;
68 Page (wxSize panel_size, int border)
71 , _panel_size (panel_size)
72 , _window_exists (false)
74 _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
80 wxWindow* create_window (wxWindow* parent)
82 _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
83 wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
87 _window_exists = true;
90 _panel->Bind (wxEVT_DESTROY, boost::bind (&Page::window_destroyed, this));
99 virtual void config_changed () = 0;
100 virtual void setup () = 0;
102 void config_changed_wrapper ()
104 if (_window_exists) {
109 void window_destroyed ()
111 _window_exists = false;
115 boost::signals2::scoped_connection _config_connection;
119 class StockPage : public wxStockPreferencesPage, public Page
122 StockPage (Kind kind, wxSize panel_size, int border)
123 : wxStockPreferencesPage (kind)
124 , Page (panel_size, border)
127 wxWindow* CreateWindow (wxWindow* parent)
129 return create_window (parent);
133 class StandardPage : public wxPreferencesPage, public Page
136 StandardPage (wxSize panel_size, int border)
137 : Page (panel_size, border)
140 wxWindow* CreateWindow (wxWindow* parent)
142 return create_window (parent);
146 class GeneralPage : public StockPage
149 GeneralPage (wxSize panel_size, int border)
150 : StockPage (Kind_General, panel_size, border)
156 wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
157 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
160 _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
161 table->Add (_set_language, wxGBPosition (r, 0));
162 _language = new wxChoice (_panel, wxID_ANY);
163 vector<pair<string, string> > languages;
164 languages.push_back (make_pair ("Čeština", "cs_CZ"));
165 languages.push_back (make_pair ("汉语/漢語", "zh_CN"));
166 languages.push_back (make_pair ("Dansk", "da_DK"));
167 languages.push_back (make_pair ("Deutsch", "de_DE"));
168 languages.push_back (make_pair ("English", "en_GB"));
169 languages.push_back (make_pair ("Español", "es_ES"));
170 languages.push_back (make_pair ("Français", "fr_FR"));
171 languages.push_back (make_pair ("Italiano", "it_IT"));
172 languages.push_back (make_pair ("Nederlands", "nl_NL"));
173 languages.push_back (make_pair ("Русский", "ru_RU"));
174 languages.push_back (make_pair ("Polski", "pl_PL"));
175 languages.push_back (make_pair ("Português europeu", "pt_PT"));
176 languages.push_back (make_pair ("Português do Brasil", "pt_BR"));
177 languages.push_back (make_pair ("Svenska", "sv_SE"));
178 languages.push_back (make_pair ("Slovenský jazyk", "sk_SK"));
179 languages.push_back (make_pair ("українська мова", "uk_UA"));
180 checked_set (_language, languages);
181 table->Add (_language, wxGBPosition (r, 1));
184 wxStaticText* restart = add_label_to_sizer (
185 table, _panel, _("(restart DCP-o-matic to see language changes)"), false, wxGBPosition (r, 0), wxGBSpan (1, 2)
187 wxFont font = restart->GetFont();
188 font.SetStyle (wxFONTSTYLE_ITALIC);
189 font.SetPointSize (font.GetPointSize() - 1);
190 restart->SetFont (font);
193 add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true, wxGBPosition (r, 0));
194 _num_local_encoding_threads = new wxSpinCtrl (_panel);
195 table->Add (_num_local_encoding_threads, wxGBPosition (r, 1));
198 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
199 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml");
200 table->Add (_cinemas_file, wxGBPosition (r, 1));
203 #ifdef DCPOMATIC_HAVE_PATCHED_FFMPEG
204 _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
205 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
209 _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
210 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
213 _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
214 table->Add (_check_for_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
217 _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates on startup"));
218 table->Add (_check_for_test_updates, wxGBPosition (r, 0), wxGBSpan (1, 2));
221 wxFlexGridSizer* bottom_table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
222 bottom_table->AddGrowableCol (1, 1);
224 add_label_to_sizer (bottom_table, _panel, _("Issuer"), true);
225 _issuer = new wxTextCtrl (_panel, wxID_ANY);
226 bottom_table->Add (_issuer, 1, wxALL | wxEXPAND);
228 add_label_to_sizer (bottom_table, _panel, _("Creator"), true);
229 _creator = new wxTextCtrl (_panel, wxID_ANY);
230 bottom_table->Add (_creator, 1, wxALL | wxEXPAND);
232 table->Add (bottom_table, wxGBPosition (r, 0), wxGBSpan (2, 2), wxEXPAND);
235 add_label_to_grid_bag_sizer (table, _panel, _("JPEG2000 encoder"), true, wxGBPosition (r, 0));
236 _encoder = new wxChoice (_panel, wxID_ANY);
237 BOOST_FOREACH (shared_ptr<JPEG2000Encoder> i, JPEG2000Encoder::all()) {
238 _encoder->Append (std_to_wx (i->name ()));
240 table->Add (_encoder, wxGBPosition (r, 1));
243 _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
244 _language->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&GeneralPage::language_changed, this));
245 _cinemas_file->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, boost::bind (&GeneralPage::cinemas_file_changed, this));
247 _num_local_encoding_threads->SetRange (1, 128);
248 _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
250 #ifdef DCPOMATIC_HAVE_PATCHED_FFMPEG
251 _analyse_ebur128->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::analyse_ebur128_changed, this));
253 _automatic_audio_analysis->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::automatic_audio_analysis_changed, this));
254 _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
255 _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
257 _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::issuer_changed, this));
258 _creator->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&GeneralPage::creator_changed, this));
261 void config_changed ()
263 Config* config = Config::instance ();
265 checked_set (_set_language, static_cast<bool>(config->language()));
267 /* Backwards compatibility of config file */
269 map<string, string> compat_map;
270 compat_map["fr"] = "fr_FR";
271 compat_map["it"] = "it_IT";
272 compat_map["es"] = "es_ES";
273 compat_map["sv"] = "sv_SE";
274 compat_map["de"] = "de_DE";
275 compat_map["nl"] = "nl_NL";
276 compat_map["ru"] = "ru_RU";
277 compat_map["pl"] = "pl_PL";
278 compat_map["da"] = "da_DK";
279 compat_map["pt"] = "pt_PT";
280 compat_map["sk"] = "sk_SK";
281 compat_map["cs"] = "cs_CZ";
282 compat_map["uk"] = "uk_UA";
284 string lang = config->language().get_value_or ("en_GB");
285 if (compat_map.find (lang) != compat_map.end ()) {
286 lang = compat_map[lang];
289 checked_set (_language, lang);
291 checked_set (_num_local_encoding_threads, config->num_local_encoding_threads ());
292 #ifdef DCPOMATIC_HAVE_PATCHED_FFMPEG
293 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
295 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
296 checked_set (_check_for_updates, config->check_for_updates ());
297 checked_set (_check_for_test_updates, config->check_for_test_updates ());
298 checked_set (_issuer, config->dcp_issuer ());
299 checked_set (_creator, config->dcp_creator ());
300 <<<<<<< 0f3c2864599f9e5a5ec001266b4aefb0205d1e1f
301 checked_set (_cinemas_file, config->cinemas_file());
303 setup_sensitivity ();
306 if (!config->encoder ()) {
307 checked_set (_encoder, 0);
309 vector<shared_ptr<JPEG2000Encoder> > encoders = JPEG2000Encoder::all ();
310 for (size_t i = 0; i < encoders.size(); ++i) {
311 if (encoders[i]->id() == config->encoder().get ()) {
312 checked_set (_encoder, i);
316 >>>>>>> Basic classes for different JPEG2000 encoders; config to choose one.
319 void setup_sensitivity ()
321 _language->Enable (_set_language->GetValue ());
322 _check_for_test_updates->Enable (_check_for_updates->GetValue ());
325 void set_language_changed ()
327 setup_sensitivity ();
328 if (_set_language->GetValue ()) {
331 Config::instance()->unset_language ();
335 void language_changed ()
337 int const sel = _language->GetSelection ();
339 Config::instance()->set_language (string_client_data (_language->GetClientObject (sel)));
341 Config::instance()->unset_language ();
345 #ifdef DCPOMATIC_HAVE_PATCHED_FFMPEG
346 void analyse_ebur128_changed ()
348 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue ());
352 void automatic_audio_analysis_changed ()
354 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue ());
357 void check_for_updates_changed ()
359 Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
362 void check_for_test_updates_changed ()
364 Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
367 void num_local_encoding_threads_changed ()
369 Config::instance()->set_num_local_encoding_threads (_num_local_encoding_threads->GetValue ());
372 void issuer_changed ()
374 Config::instance()->set_dcp_issuer (wx_to_std (_issuer->GetValue ()));
377 void creator_changed ()
379 Config::instance()->set_dcp_creator (wx_to_std (_creator->GetValue ()));
382 void cinemas_file_changed ()
384 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
387 wxCheckBox* _set_language;
389 wxSpinCtrl* _num_local_encoding_threads;
390 FilePickerCtrl* _cinemas_file;
391 #ifdef DCPOMATIC_HAVE_PATCHED_FFMPEG
392 wxCheckBox* _analyse_ebur128;
394 wxCheckBox* _automatic_audio_analysis;
395 wxCheckBox* _check_for_updates;
396 wxCheckBox* _check_for_test_updates;
398 wxTextCtrl* _creator;
402 class DefaultsPage : public StandardPage
405 DefaultsPage (wxSize panel_size, int border)
406 : StandardPage (panel_size, border)
409 wxString GetName () const
411 return _("Defaults");
415 wxBitmap GetLargeIcon () const
417 return wxBitmap ("defaults", wxBITMAP_TYPE_PNG_RESOURCE);
424 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
425 table->AddGrowableCol (1, 1);
426 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
429 add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
430 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
431 _still_length = new wxSpinCtrl (_panel);
432 s->Add (_still_length);
433 add_label_to_sizer (s, _panel, _("s"), false);
437 add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
438 #ifdef DCPOMATIC_USE_OWN_PICKER
439 _directory = new DirPickerCtrl (_panel);
441 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
443 table->Add (_directory, 1, wxEXPAND);
445 add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
446 _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
447 table->Add (_isdcf_metadata_button);
449 add_label_to_sizer (table, _panel, _("Default container"), true);
450 _container = new wxChoice (_panel, wxID_ANY);
451 table->Add (_container);
453 add_label_to_sizer (table, _panel, _("Default content type"), true);
454 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
455 table->Add (_dcp_content_type);
458 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
459 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
460 _j2k_bandwidth = new wxSpinCtrl (_panel);
461 s->Add (_j2k_bandwidth);
462 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
467 add_label_to_sizer (table, _panel, _("Default audio delay"), true);
468 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
469 _audio_delay = new wxSpinCtrl (_panel);
470 s->Add (_audio_delay);
471 add_label_to_sizer (s, _panel, _("ms"), false);
475 add_label_to_sizer (table, _panel, _("Default standard"), true);
476 _standard = new wxChoice (_panel, wxID_ANY);
477 table->Add (_standard);
479 _still_length->SetRange (1, 3600);
480 _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
482 _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
484 _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
486 vector<Ratio const *> ratios = Ratio::all ();
487 for (size_t i = 0; i < ratios.size(); ++i) {
488 _container->Append (std_to_wx (ratios[i]->nickname ()));
491 _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
493 vector<DCPContentType const *> const ct = DCPContentType::all ();
494 for (size_t i = 0; i < ct.size(); ++i) {
495 _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
498 _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
500 _j2k_bandwidth->SetRange (50, 250);
501 _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
503 _audio_delay->SetRange (-1000, 1000);
504 _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
506 _standard->Append (_("SMPTE"));
507 _standard->Append (_("Interop"));
508 _standard->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::standard_changed, this));
511 void config_changed ()
513 Config* config = Config::instance ();
515 vector<Ratio const *> ratios = Ratio::all ();
516 for (size_t i = 0; i < ratios.size(); ++i) {
517 if (ratios[i] == config->default_container ()) {
518 _container->SetSelection (i);
522 vector<DCPContentType const *> const ct = DCPContentType::all ();
523 for (size_t i = 0; i < ct.size(); ++i) {
524 if (ct[i] == config->default_dcp_content_type ()) {
525 _dcp_content_type->SetSelection (i);
529 checked_set (_still_length, config->default_still_length ());
530 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
531 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
532 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
533 checked_set (_audio_delay, config->default_audio_delay ());
534 checked_set (_standard, config->default_interop() ? 1 : 0);
537 void j2k_bandwidth_changed ()
539 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
542 void audio_delay_changed ()
544 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
547 void directory_changed ()
549 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
552 void edit_isdcf_metadata_clicked ()
554 ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata (), false);
556 Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
560 void still_length_changed ()
562 Config::instance()->set_default_still_length (_still_length->GetValue ());
565 void container_changed ()
567 vector<Ratio const *> ratio = Ratio::all ();
568 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
571 void dcp_content_type_changed ()
573 vector<DCPContentType const *> ct = DCPContentType::all ();
574 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
577 void standard_changed ()
579 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
582 wxSpinCtrl* _j2k_bandwidth;
583 wxSpinCtrl* _audio_delay;
584 wxButton* _isdcf_metadata_button;
585 wxSpinCtrl* _still_length;
586 #ifdef DCPOMATIC_USE_OWN_PICKER
587 DirPickerCtrl* _directory;
589 wxDirPickerCtrl* _directory;
591 wxChoice* _container;
592 wxChoice* _dcp_content_type;
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 ())));
780 update_certificate_list ();
781 } catch (dcp::MiscError& e) {
782 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
788 update_sensitivity ();
791 void remove_certificate ()
793 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
798 _certificates->DeleteItem (i);
802 update_sensitivity ();
805 void export_certificate ()
807 int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
812 wxFileDialog* d = new wxFileDialog (
813 this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
814 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
817 dcp::CertificateChain::List all = _chain->root_to_leaf ();
818 dcp::CertificateChain::List::iterator j = all.begin ();
819 for (int k = 0; k < i; ++k) {
823 if (d->ShowModal () == wxID_OK) {
824 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
826 throw OpenFileError (wx_to_std (d->GetPath ()));
829 string const s = j->certificate (true);
830 fwrite (s.c_str(), 1, s.length(), f);
836 void update_certificate_list ()
838 _certificates->DeleteAllItems ();
840 dcp::CertificateChain::List certs = _chain->root_to_leaf ();
841 BOOST_FOREACH (dcp::Certificate const & i, certs) {
844 _certificates->InsertItem (item);
845 _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
848 _certificates->SetItem (n, 0, _("Root"));
849 } else if (n == (certs.size() - 1)) {
850 _certificates->SetItem (n, 0, _("Leaf"));
852 _certificates->SetItem (n, 0, _("Intermediate"));
859 void remake_certificates ()
861 shared_ptr<const dcp::CertificateChain> chain = _get ();
863 string subject_organization_name;
864 string subject_organizational_unit_name;
865 string root_common_name;
866 string intermediate_common_name;
867 string leaf_common_name;
869 dcp::CertificateChain::List all = chain->root_to_leaf ();
871 if (all.size() >= 1) {
873 subject_organization_name = chain->root().subject_organization_name ();
874 subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
875 root_common_name = chain->root().subject_common_name ();
878 if (all.size() >= 2) {
880 leaf_common_name = chain->leaf().subject_common_name ();
883 if (all.size() >= 3) {
884 /* Have an intermediate */
885 dcp::CertificateChain::List::iterator i = all.begin ();
887 intermediate_common_name = i->subject_common_name ();
890 MakeChainDialog* d = new MakeChainDialog (
892 subject_organization_name,
893 subject_organizational_unit_name,
895 intermediate_common_name,
899 if (d->ShowModal () == wxID_OK) {
901 new dcp::CertificateChain (
904 d->organisational_unit (),
905 d->root_common_name (),
906 d->intermediate_common_name (),
907 d->leaf_common_name ()
912 update_certificate_list ();
913 update_private_key ();
919 void update_sensitivity ()
921 _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
922 _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
925 void update_private_key ()
927 checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
931 void load_private_key ()
933 wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
935 if (d->ShowModal() == wxID_OK) {
937 boost::filesystem::path p (wx_to_std (d->GetPath ()));
938 if (boost::filesystem::file_size (p) > 1024) {
939 error_dialog (this, wxString::Format (_("Could not read key file (%s)"), std_to_wx (p.string ())));
943 _chain->set_key (dcp::file_to_string (p));
945 update_private_key ();
946 } catch (dcp::MiscError& e) {
947 error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
953 update_sensitivity ();
956 void export_private_key ()
958 optional<string> key = _chain->key ();
963 wxFileDialog* d = new wxFileDialog (
964 this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
965 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
968 if (d->ShowModal () == wxID_OK) {
969 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
971 throw OpenFileError (wx_to_std (d->GetPath ()));
974 string const s = _chain->key().get ();
975 fwrite (s.c_str(), 1, s.length(), f);
981 wxListCtrl* _certificates;
982 wxButton* _add_certificate;
983 wxButton* _export_certificate;
984 wxButton* _remove_certificate;
985 wxButton* _remake_certificates;
986 wxStaticText* _private_key;
987 wxButton* _load_private_key;
988 wxButton* _export_private_key;
990 wxBoxSizer* _button_sizer;
991 shared_ptr<dcp::CertificateChain> _chain;
992 boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
993 boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
996 class KeysPage : public StandardPage
999 KeysPage (wxSize panel_size, int border)
1000 : StandardPage (panel_size, border)
1003 wxString GetName () const
1008 #ifdef DCPOMATIC_OSX
1009 wxBitmap GetLargeIcon () const
1011 return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
1019 _signer = new CertificateChainEditor (
1020 _panel, _("Signing DCPs and KDMs"), _border,
1021 boost::bind (&Config::set_signer_chain, Config::instance (), _1),
1022 boost::bind (&Config::signer_chain, Config::instance ())
1025 _panel->GetSizer()->Add (_signer);
1027 _decryption = new CertificateChainEditor (
1028 _panel, _("Decrypting DCPs"), _border,
1029 boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
1030 boost::bind (&Config::decryption_chain, Config::instance ())
1033 _panel->GetSizer()->Add (_decryption);
1035 _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export DCP decryption certificate..."));
1036 _decryption->add_button (_export_decryption_certificate);
1038 _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
1041 void export_decryption_certificate ()
1043 wxFileDialog* d = new wxFileDialog (
1044 _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
1045 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
1048 if (d->ShowModal () == wxID_OK) {
1049 FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
1051 throw OpenFileError (wx_to_std (d->GetPath ()));
1054 string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
1055 fwrite (s.c_str(), 1, s.length(), f);
1061 void config_changed ()
1063 _signer->config_changed ();
1064 _decryption->config_changed ();
1067 CertificateChainEditor* _signer;
1068 CertificateChainEditor* _decryption;
1069 wxButton* _export_decryption_certificate;
1072 class TMSPage : public StandardPage
1075 TMSPage (wxSize panel_size, int border)
1076 : StandardPage (panel_size, border)
1079 wxString GetName () const
1084 #ifdef DCPOMATIC_OSX
1085 wxBitmap GetLargeIcon () const
1087 return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
1094 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1095 table->AddGrowableCol (1, 1);
1096 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1098 add_label_to_sizer (table, _panel, _("Protocol"), true);
1099 _tms_protocol = new wxChoice (_panel, wxID_ANY);
1100 table->Add (_tms_protocol, 1, wxEXPAND);
1102 add_label_to_sizer (table, _panel, _("IP address"), true);
1103 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
1104 table->Add (_tms_ip, 1, wxEXPAND);
1106 add_label_to_sizer (table, _panel, _("Target path"), true);
1107 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
1108 table->Add (_tms_path, 1, wxEXPAND);
1110 add_label_to_sizer (table, _panel, _("User name"), true);
1111 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
1112 table->Add (_tms_user, 1, wxEXPAND);
1114 add_label_to_sizer (table, _panel, _("Password"), true);
1115 _tms_password = new wxTextCtrl (_panel, wxID_ANY);
1116 table->Add (_tms_password, 1, wxEXPAND);
1118 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
1119 _tms_protocol->Append (_("FTP (for Dolby)"));
1121 _tms_protocol->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&TMSPage::tms_protocol_changed, this));
1122 _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
1123 _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
1124 _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
1125 _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
1128 void config_changed ()
1130 Config* config = Config::instance ();
1132 checked_set (_tms_protocol, config->tms_protocol ());
1133 checked_set (_tms_ip, config->tms_ip ());
1134 checked_set (_tms_path, config->tms_path ());
1135 checked_set (_tms_user, config->tms_user ());
1136 checked_set (_tms_password, config->tms_password ());
1139 void tms_protocol_changed ()
1141 Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
1144 void tms_ip_changed ()
1146 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
1149 void tms_path_changed ()
1151 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
1154 void tms_user_changed ()
1156 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
1159 void tms_password_changed ()
1161 Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
1164 wxChoice* _tms_protocol;
1165 wxTextCtrl* _tms_ip;
1166 wxTextCtrl* _tms_path;
1167 wxTextCtrl* _tms_user;
1168 wxTextCtrl* _tms_password;
1177 class KDMEmailPage : public StandardPage
1181 KDMEmailPage (wxSize panel_size, int border)
1182 #ifdef DCPOMATIC_OSX
1183 /* We have to force both width and height of this one */
1184 : StandardPage (wxSize (480, 128), border)
1186 : StandardPage (panel_size, border)
1190 wxString GetName () const
1192 return _("KDM Email");
1195 #ifdef DCPOMATIC_OSX
1196 wxBitmap GetLargeIcon () const
1198 return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
1205 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1206 table->AddGrowableCol (1, 1);
1207 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
1209 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
1211 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1212 _mail_server = new wxTextCtrl (_panel, wxID_ANY);
1213 s->Add (_mail_server, 1, wxEXPAND | wxALL);
1214 add_label_to_sizer (s, _panel, _("port"), false);
1215 _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
1216 _mail_port->SetRange (0, 65535);
1217 s->Add (_mail_port);
1218 table->Add (s, 1, wxEXPAND | wxALL);
1221 add_label_to_sizer (table, _panel, _("Mail user name"), true);
1222 _mail_user = new wxTextCtrl (_panel, wxID_ANY);
1223 table->Add (_mail_user, 1, wxEXPAND | wxALL);
1225 add_label_to_sizer (table, _panel, _("Mail password"), true);
1226 _mail_password = new wxTextCtrl (_panel, wxID_ANY);
1227 table->Add (_mail_password, 1, wxEXPAND | wxALL);
1229 add_label_to_sizer (table, _panel, _("Subject"), true);
1230 _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
1231 table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
1233 add_label_to_sizer (table, _panel, _("From address"), true);
1234 _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
1235 table->Add (_kdm_from, 1, wxEXPAND | wxALL);
1237 vector<string> columns;
1238 columns.push_back (wx_to_std (_("Address")));
1239 add_label_to_sizer (table, _panel, _("CC addresses"), true);
1240 _kdm_cc = new EditableList<string, EmailDialog> (
1243 bind (&Config::kdm_cc, Config::instance()),
1244 bind (&Config::set_kdm_cc, Config::instance(), _1),
1245 bind (&string_not_empty, _1),
1248 table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
1250 add_label_to_sizer (table, _panel, _("BCC address"), true);
1251 _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
1252 table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
1254 _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1255 _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
1257 _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
1258 _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
1262 _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
1263 _mail_port->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&KDMEmailPage::mail_port_changed, this));
1264 _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
1265 _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
1266 _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1267 _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1268 _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1269 _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1270 _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
1273 void config_changed ()
1275 Config* config = Config::instance ();
1277 checked_set (_mail_server, config->mail_server ());
1278 checked_set (_mail_port, config->mail_port ());
1279 checked_set (_mail_user, config->mail_user ());
1280 checked_set (_mail_password, config->mail_password ());
1281 checked_set (_kdm_subject, config->kdm_subject ());
1282 checked_set (_kdm_from, config->kdm_from ());
1283 checked_set (_kdm_bcc, config->kdm_bcc ());
1284 checked_set (_kdm_email, Config::instance()->kdm_email ());
1287 void mail_server_changed ()
1289 Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
1292 void mail_port_changed ()
1294 Config::instance()->set_mail_port (_mail_port->GetValue ());
1297 void mail_user_changed ()
1299 Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
1302 void mail_password_changed ()
1304 Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
1307 void kdm_subject_changed ()
1309 Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
1312 void kdm_from_changed ()
1314 Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
1317 void kdm_bcc_changed ()
1319 Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
1322 void kdm_email_changed ()
1324 if (_kdm_email->GetValue().IsEmpty ()) {
1325 /* Sometimes we get sent an erroneous notification that the email
1326 is empty; I don't know why.
1330 Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
1333 void reset_kdm_email ()
1335 Config::instance()->reset_kdm_email ();
1336 checked_set (_kdm_email, Config::instance()->kdm_email ());
1339 wxTextCtrl* _mail_server;
1340 wxSpinCtrl* _mail_port;
1341 wxTextCtrl* _mail_user;
1342 wxTextCtrl* _mail_password;
1343 wxTextCtrl* _kdm_subject;
1344 wxTextCtrl* _kdm_from;
1345 EditableList<string, EmailDialog>* _kdm_cc;
1346 wxTextCtrl* _kdm_bcc;
1347 wxTextCtrl* _kdm_email;
1348 wxButton* _reset_kdm_email;
1351 /** @class AdvancedPage
1352 * @brief Advanced page of the preferences dialog.
1354 class AdvancedPage : public StockPage
1357 AdvancedPage (wxSize panel_size, int border)
1358 : StockPage (Kind_Advanced, panel_size, border)
1359 , _maximum_j2k_bandwidth (0)
1360 , _allow_any_dcp_frame_rate (0)
1361 , _only_servers_encode (0)
1366 , _log_debug_decode (0)
1367 , _log_debug_encode (0)
1368 , _log_debug_email (0)
1374 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1375 table->AddGrowableCol (1, 1);
1376 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1379 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
1380 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1381 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1382 s->Add (_maximum_j2k_bandwidth, 1);
1383 add_label_to_sizer (s, _panel, _("Mbit/s"), false);
1387 _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
1388 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1389 table->AddSpacer (0);
1391 _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
1392 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1393 table->AddSpacer (0);
1396 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log:"));
1397 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
1399 wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log"));
1400 table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
1404 wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
1405 _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
1406 t->Add (_log_general, 1, wxEXPAND | wxALL);
1407 _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
1408 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1409 _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
1410 t->Add (_log_error, 1, wxEXPAND | wxALL);
1411 _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
1412 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1413 _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
1414 t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
1415 _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
1416 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1417 _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
1418 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1419 table->Add (t, 0, wxALL, 6);
1422 #ifdef DCPOMATIC_WINDOWS
1423 _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
1424 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1425 table->AddSpacer (0);
1428 _maximum_j2k_bandwidth->SetRange (1, 1000);
1429 _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1430 _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1431 _only_servers_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1432 _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1433 _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1434 _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1435 _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1436 _log_debug_decode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1437 _log_debug_encode->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1438 _log_debug_email->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
1439 #ifdef DCPOMATIC_WINDOWS
1440 _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
1444 void config_changed ()
1446 Config* config = Config::instance ();
1448 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1449 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1450 checked_set (_only_servers_encode, config->only_servers_encode ());
1451 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1452 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1453 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1454 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1455 checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
1456 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1457 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1458 #ifdef DCPOMATIC_WINDOWS
1459 checked_set (_win32_console, config->win32_console());
1463 void maximum_j2k_bandwidth_changed ()
1465 Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
1468 void allow_any_dcp_frame_rate_changed ()
1470 Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
1473 void only_servers_encode_changed ()
1475 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
1481 if (_log_general->GetValue ()) {
1482 types |= LogEntry::TYPE_GENERAL;
1484 if (_log_warning->GetValue ()) {
1485 types |= LogEntry::TYPE_WARNING;
1487 if (_log_error->GetValue ()) {
1488 types |= LogEntry::TYPE_ERROR;
1490 if (_log_timing->GetValue ()) {
1491 types |= LogEntry::TYPE_TIMING;
1493 if (_log_debug_decode->GetValue ()) {
1494 types |= LogEntry::TYPE_DEBUG_DECODE;
1496 if (_log_debug_encode->GetValue ()) {
1497 types |= LogEntry::TYPE_DEBUG_ENCODE;
1499 if (_log_debug_email->GetValue ()) {
1500 types |= LogEntry::TYPE_DEBUG_EMAIL;
1502 Config::instance()->set_log_types (types);
1505 #ifdef DCPOMATIC_WINDOWS
1506 void win32_console_changed ()
1508 Config::instance()->set_win32_console (_win32_console->GetValue ());
1512 wxSpinCtrl* _maximum_j2k_bandwidth;
1513 wxCheckBox* _allow_any_dcp_frame_rate;
1514 wxCheckBox* _only_servers_encode;
1515 wxCheckBox* _log_general;
1516 wxCheckBox* _log_warning;
1517 wxCheckBox* _log_error;
1518 wxCheckBox* _log_timing;
1519 wxCheckBox* _log_debug_decode;
1520 wxCheckBox* _log_debug_encode;
1521 wxCheckBox* _log_debug_email;
1522 #ifdef DCPOMATIC_WINDOWS
1523 wxCheckBox* _win32_console;
1527 wxPreferencesEditor*
1528 create_config_dialog ()
1530 wxPreferencesEditor* e = new wxPreferencesEditor ();
1532 #ifdef DCPOMATIC_OSX
1533 /* Width that we force some of the config panels to be on OSX so that
1534 the containing window doesn't shrink too much when we select those panels.
1535 This is obviously an unpleasant hack.
1537 wxSize ps = wxSize (520, -1);
1538 int const border = 16;
1540 wxSize ps = wxSize (-1, -1);
1541 int const border = 8;
1544 e->AddPage (new GeneralPage (ps, border));
1545 e->AddPage (new DefaultsPage (ps, border));
1546 e->AddPage (new EncodingServersPage (ps, border));
1547 e->AddPage (new KeysPage (ps, border));
1548 e->AddPage (new TMSPage (ps, border));
1549 e->AddPage (new KDMEmailPage (ps, border));
1550 e->AddPage (new AdvancedPage (ps, border));