2 Copyright (C) 2012-2021 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/>.
22 /** @file src/full_config_dialog.cc
23 * @brief A dialogue to edit all DCP-o-matic configuration.
27 #include "check_box.h"
28 #include "config_dialog.h"
29 #include "config_move_dialog.h"
30 #include "dcpomatic_button.h"
31 #include "dir_picker_ctrl.h"
32 #include "editable_list.h"
33 #include "email_dialog.h"
34 #include "file_picker_ctrl.h"
35 #include "filter_dialog.h"
36 #include "full_config_dialog.h"
37 #include "kdm_choice.h"
38 #include "make_chain_dialog.h"
39 #include "nag_dialog.h"
40 #include "name_format_editor.h"
41 #include "password_entry.h"
42 #include "send_test_email_dialog.h"
43 #include "server_dialog.h"
44 #include "static_text.h"
46 #include "lib/config.h"
47 #include "lib/cross.h"
48 #include "lib/dcp_content_type.h"
49 #include "lib/emailer.h"
50 #include "lib/exceptions.h"
51 #include "lib/filter.h"
53 #include "lib/ratio.h"
55 #include <dcp/certificate_chain.h>
56 #include <dcp/exceptions.h>
57 #include <dcp/locale_convert.h>
58 #include <dcp/warnings.h>
59 LIBDCP_DISABLE_WARNINGS
60 #include <wx/filepicker.h>
61 #include <wx/preferences.h>
62 #include <wx/spinctrl.h>
63 #include <wx/stdpaths.h>
64 LIBDCP_ENABLE_WARNINGS
66 #include <boost/filesystem.hpp>
76 using std::shared_ptr;
80 using boost::optional;
81 #if BOOST_VERSION >= 106100
82 using namespace boost::placeholders;
84 using dcp::locale_convert;
87 class FullGeneralPage : public GeneralPage
90 FullGeneralPage (wxSize panel_size, int border)
91 : GeneralPage (panel_size, border)
95 void setup () override
97 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
98 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
101 add_language_controls (table, r);
103 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
104 _master_encoding_threads = new wxSpinCtrl (_panel);
105 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
108 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
109 _server_encoding_threads = new wxSpinCtrl (_panel);
110 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
113 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
114 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
115 table->Add (_config_file, wxGBPosition (r, 1));
118 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
119 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
120 table->Add (_cinemas_file, wxGBPosition (r, 1));
121 Button* export_cinemas = new Button (_panel, _("Export..."));
122 table->Add (export_cinemas, wxGBPosition (r, 2));
125 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
126 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
127 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
131 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
132 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
135 add_update_controls (table, r);
137 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
138 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
140 _master_encoding_threads->SetRange (1, 128);
141 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
142 _server_encoding_threads->SetRange (1, 128);
143 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
144 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
146 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
147 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
149 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
152 void config_changed () override
154 auto config = Config::instance ();
156 checked_set (_master_encoding_threads, config->master_encoding_threads ());
157 checked_set (_server_encoding_threads, config->server_encoding_threads ());
158 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
159 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
161 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
162 checked_set (_config_file, config->config_read_file());
163 checked_set (_cinemas_file, config->cinemas_file());
165 GeneralPage::config_changed ();
168 void export_cinemas_file ()
170 auto d = new wxFileDialog (
171 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
172 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
175 if (d->ShowModal () == wxID_OK) {
176 boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
181 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
182 void analyse_ebur128_changed ()
184 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
188 void automatic_audio_analysis_changed ()
190 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
193 void master_encoding_threads_changed ()
195 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
198 void server_encoding_threads_changed ()
200 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
203 void config_file_changed ()
205 auto config = Config::instance();
206 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
207 if (new_file == config->config_read_file()) {
210 bool copy_and_link = true;
211 if (boost::filesystem::exists(new_file)) {
212 auto d = new ConfigMoveDialog (_panel, new_file);
213 if (d->ShowModal() == wxID_OK) {
214 copy_and_link = false;
221 if (new_file != config->config_read_file()) {
222 config->copy_and_link (new_file);
225 config->link (new_file);
229 void cinemas_file_changed ()
231 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
234 wxSpinCtrl* _master_encoding_threads;
235 wxSpinCtrl* _server_encoding_threads;
236 FilePickerCtrl* _config_file;
237 FilePickerCtrl* _cinemas_file;
238 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
239 wxCheckBox* _analyse_ebur128;
241 wxCheckBox* _automatic_audio_analysis;
245 class DefaultsPage : public Page
248 DefaultsPage (wxSize panel_size, int border)
249 : Page (panel_size, border)
252 wxString GetName () const override
254 return _("Defaults");
258 wxBitmap GetLargeIcon () const override
260 return wxBitmap(bitmap_path("defaults"), wxBITMAP_TYPE_PNG);
265 void setup () override
267 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
268 table->AddGrowableCol (1, 1);
269 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
272 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
273 auto s = new wxBoxSizer (wxHORIZONTAL);
274 _still_length = new wxSpinCtrl (_panel);
275 s->Add (_still_length);
276 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
280 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
281 #ifdef DCPOMATIC_USE_OWN_PICKER
282 _directory = new DirPickerCtrl (_panel);
284 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
286 table->Add (_directory, 1, wxEXPAND);
288 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
289 _container = new wxChoice (_panel, wxID_ANY);
290 table->Add (_container);
292 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
293 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
294 table->Add (_dcp_content_type);
296 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
297 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
298 table->Add (_dcp_audio_channels);
301 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
302 auto s = new wxBoxSizer (wxHORIZONTAL);
303 _j2k_bandwidth = new wxSpinCtrl (_panel);
304 s->Add (_j2k_bandwidth);
305 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
310 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
311 auto s = new wxBoxSizer (wxHORIZONTAL);
312 _audio_delay = new wxSpinCtrl (_panel);
313 s->Add (_audio_delay);
314 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
318 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
319 _standard = new wxChoice (_panel, wxID_ANY);
320 table->Add (_standard);
322 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
323 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
325 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
326 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
328 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
329 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
331 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
332 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
334 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
335 #ifdef DCPOMATIC_USE_OWN_PICKER
336 _kdm_directory = new DirPickerCtrl (_panel);
338 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
340 table->Add (_kdm_directory, 1, wxEXPAND);
342 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
343 _kdm_type = new KDMChoice (_panel);
344 table->Add (_kdm_type, 1, wxEXPAND);
346 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
348 _still_length->SetRange (1, 3600);
349 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
351 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
352 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
353 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
355 _use_isdcf_name_by_default->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::use_isdcf_name_by_default_changed, this));
357 for (auto i: Ratio::containers()) {
358 _container->Append (std_to_wx(i->container_nickname()));
361 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
363 for (auto i: DCPContentType::all()) {
364 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
367 setup_audio_channels_choice (_dcp_audio_channels, 2);
369 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
370 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
372 _j2k_bandwidth->SetRange (50, 250);
373 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
375 _audio_delay->SetRange (-1000, 1000);
376 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
378 _standard->Append (_("SMPTE"));
379 _standard->Append (_("Interop"));
380 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
382 for (auto const& i: _enable_metadata) {
383 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
386 for (auto const& i: _metadata) {
387 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
391 void config_changed () override
393 auto config = Config::instance ();
395 auto containers = Ratio::containers ();
396 for (size_t i = 0; i < containers.size(); ++i) {
397 if (containers[i] == config->default_container()) {
398 _container->SetSelection (i);
402 auto const ct = DCPContentType::all ();
403 for (size_t i = 0; i < ct.size(); ++i) {
404 if (ct[i] == config->default_dcp_content_type()) {
405 _dcp_content_type->SetSelection (i);
409 checked_set (_still_length, config->default_still_length ());
410 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
411 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
412 _kdm_type->set (config->default_kdm_type());
413 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
414 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
415 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
416 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
417 checked_set (_audio_delay, config->default_audio_delay ());
418 checked_set (_standard, config->default_interop() ? 1 : 0);
420 auto metadata = config->default_metadata();
422 for (auto const& i: metadata) {
423 _enable_metadata[i.first]->SetValue(true);
424 checked_set (_metadata[i.first], i.second);
427 for (auto const& i: _enable_metadata) {
428 if (metadata.find(i.first) == metadata.end()) {
429 checked_set (i.second, false);
433 for (auto const& i: _metadata) {
434 if (metadata.find(i.first) == metadata.end()) {
435 checked_set (i.second, wxT(""));
439 setup_sensitivity ();
442 void j2k_bandwidth_changed ()
444 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
447 void audio_delay_changed ()
449 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
452 void dcp_audio_channels_changed ()
454 int const s = _dcp_audio_channels->GetSelection ();
455 if (s != wxNOT_FOUND) {
456 Config::instance()->set_default_dcp_audio_channels (
457 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
462 void directory_changed ()
464 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
467 void kdm_directory_changed ()
469 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
472 void kdm_type_changed ()
474 Config::instance()->set_default_kdm_type(_kdm_type->get());
477 void use_isdcf_name_by_default_changed ()
479 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
482 void still_length_changed ()
484 Config::instance()->set_default_still_length (_still_length->GetValue ());
487 void container_changed ()
489 auto ratio = Ratio::containers ();
490 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
493 void dcp_content_type_changed ()
495 auto ct = DCPContentType::all ();
496 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
499 void standard_changed ()
501 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
504 void metadata_changed ()
506 map<string, string> metadata;
507 for (auto const& i: _enable_metadata) {
508 if (i.second->GetValue()) {
509 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
512 Config::instance()->set_default_metadata (metadata);
513 setup_sensitivity ();
516 void setup_sensitivity ()
518 for (auto const& i: _enable_metadata) {
519 _metadata[i.first]->Enable(i.second->GetValue());
523 wxSpinCtrl* _j2k_bandwidth;
524 wxSpinCtrl* _audio_delay;
525 wxSpinCtrl* _still_length;
526 #ifdef DCPOMATIC_USE_OWN_PICKER
527 DirPickerCtrl* _directory;
528 DirPickerCtrl* _kdm_directory;
530 wxDirPickerCtrl* _directory;
531 wxDirPickerCtrl* _kdm_directory;
533 KDMChoice* _kdm_type;
534 wxCheckBox* _use_isdcf_name_by_default;
535 wxChoice* _container;
536 wxChoice* _dcp_content_type;
537 wxChoice* _dcp_audio_channels;
539 map<string, CheckBox*> _enable_metadata;
540 map<string, wxTextCtrl*> _metadata;
544 class EncodingServersPage : public Page
547 EncodingServersPage (wxSize panel_size, int border)
548 : Page (panel_size, border)
551 wxString GetName () const override
557 wxBitmap GetLargeIcon () const override
559 return wxBitmap(bitmap_path("servers"), wxBITMAP_TYPE_PNG);
564 void setup () override
566 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
567 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
569 vector<EditableListColumn> columns;
570 columns.push_back (EditableListColumn(_("IP address / host name")));
571 _servers_list = new EditableList<string, ServerDialog> (
574 boost::bind (&Config::servers, Config::instance()),
575 boost::bind (&Config::set_servers, Config::instance(), _1),
576 boost::bind (&EncodingServersPage::server_column, this, _1)
579 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
581 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
584 void config_changed () override
586 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
587 _servers_list->refresh ();
590 void use_any_servers_changed ()
592 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
595 string server_column (string s)
600 wxCheckBox* _use_any_servers;
601 EditableList<string, ServerDialog>* _servers_list;
605 class TMSPage : public Page
608 TMSPage (wxSize panel_size, int border)
609 : Page (panel_size, border)
612 wxString GetName () const override
618 wxBitmap GetLargeIcon () const override
620 return wxBitmap(bitmap_path("tms"), wxBITMAP_TYPE_PNG);
625 void setup () override
627 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
628 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
630 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
631 table->AddGrowableCol (1, 1);
632 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
634 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
635 _tms_protocol = new wxChoice (_panel, wxID_ANY);
636 table->Add (_tms_protocol, 1, wxEXPAND);
638 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
639 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
640 table->Add (_tms_ip, 1, wxEXPAND);
642 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
643 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
644 table->Add (_tms_path, 1, wxEXPAND);
646 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
647 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
648 table->Add (_tms_user, 1, wxEXPAND);
650 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
651 _tms_password = new PasswordEntry (_panel);
652 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
654 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
655 _tms_protocol->Append (_("FTP (for Dolby)"));
657 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
658 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
659 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
660 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
661 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
662 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
665 void config_changed () override
667 auto config = Config::instance ();
669 checked_set (_upload, config->upload_after_make_dcp());
670 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
671 checked_set (_tms_ip, config->tms_ip ());
672 checked_set (_tms_path, config->tms_path ());
673 checked_set (_tms_user, config->tms_user ());
674 checked_set (_tms_password, config->tms_password ());
677 void upload_changed ()
679 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
682 void tms_protocol_changed ()
684 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
687 void tms_ip_changed ()
689 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
692 void tms_path_changed ()
694 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
697 void tms_user_changed ()
699 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
702 void tms_password_changed ()
704 Config::instance()->set_tms_password (_tms_password->get());
708 wxChoice* _tms_protocol;
710 wxTextCtrl* _tms_path;
711 wxTextCtrl* _tms_user;
712 PasswordEntry* _tms_password;
716 class EmailPage : public Page
719 EmailPage (wxSize panel_size, int border)
720 : Page (panel_size, border)
723 wxString GetName () const override
729 wxBitmap GetLargeIcon () const override
731 return wxBitmap(bitmap_path("email"), wxBITMAP_TYPE_PNG);
736 void setup () override
738 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
739 table->AddGrowableCol (1, 1);
740 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
742 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
744 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
745 _server = new wxTextCtrl (_panel, wxID_ANY);
746 s->Add (_server, 1, wxEXPAND | wxALL);
747 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
748 _port = new wxSpinCtrl (_panel, wxID_ANY);
749 _port->SetRange (0, 65535);
751 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
752 _protocol = new wxChoice (_panel, wxID_ANY);
753 /* Make sure this matches the switches in config_changed and port_changed below */
754 _protocol->Append (_("Auto"));
755 _protocol->Append (_("Plain"));
756 _protocol->Append (_("STARTTLS"));
757 _protocol->Append (_("SSL"));
758 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
759 table->Add (s, 1, wxEXPAND | wxALL);
762 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
763 _user = new wxTextCtrl (_panel, wxID_ANY);
764 table->Add (_user, 1, wxEXPAND | wxALL);
766 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
767 _password = new PasswordEntry (_panel);
768 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
770 table->AddSpacer (0);
771 _send_test_email = new Button (_panel, _("Send test email..."));
772 table->Add (_send_test_email);
774 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
775 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
776 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
777 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
778 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
779 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
782 void config_changed () override
784 auto config = Config::instance ();
786 checked_set (_server, config->mail_server());
787 checked_set (_port, config->mail_port());
788 switch (config->mail_protocol()) {
789 case EmailProtocol::AUTO:
790 checked_set (_protocol, 0);
792 case EmailProtocol::PLAIN:
793 checked_set (_protocol, 1);
795 case EmailProtocol::STARTTLS:
796 checked_set (_protocol, 2);
798 case EmailProtocol::SSL:
799 checked_set (_protocol, 3);
802 checked_set (_user, config->mail_user());
803 checked_set (_password, config->mail_password());
806 void server_changed ()
808 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
813 Config::instance()->set_mail_port(_port->GetValue());
816 void protocol_changed ()
818 switch (_protocol->GetSelection()) {
820 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
823 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
826 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
829 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
836 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
839 void password_changed ()
841 Config::instance()->set_mail_password(_password->get());
844 void send_test_email_clicked ()
846 auto dialog = new SendTestEmailDialog(_panel);
847 auto result = dialog->ShowModal();
849 if (result == wxID_OK) {
851 wx_to_std(dialog->from()),
852 { wx_to_std(dialog->to()) },
853 wx_to_std(_("DCP-o-matic test email")),
854 wx_to_std(_("This is a test email from DCP-o-matic."))
856 auto config = Config::instance();
858 emailer.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
859 } catch (NetworkError& e) {
860 error_dialog (_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
862 } catch (std::exception& e) {
863 error_dialog (_panel, _("Test email sending failed."), std_to_wx(e.what()));
866 error_dialog (_panel, _("Test email sending failed."));
869 message_dialog (_panel, _("Test email sent."));
877 PasswordEntry* _password;
878 Button* _send_test_email;
882 class KDMEmailPage : public Page
886 KDMEmailPage (wxSize panel_size, int border)
888 /* We have to force both width and height of this one */
889 : Page (wxSize (panel_size.GetWidth(), 128), border)
891 : Page (panel_size, border)
895 wxString GetName () const override
897 return _("KDM Email");
901 wxBitmap GetLargeIcon () const override
903 return wxBitmap(bitmap_path("kdm_email"), wxBITMAP_TYPE_PNG);
908 void setup () override
910 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
911 table->AddGrowableCol (1, 1);
912 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
914 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
915 _subject = new wxTextCtrl (_panel, wxID_ANY);
916 table->Add (_subject, 1, wxEXPAND | wxALL);
918 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
919 _from = new wxTextCtrl (_panel, wxID_ANY);
920 table->Add (_from, 1, wxEXPAND | wxALL);
922 vector<EditableListColumn> columns;
923 columns.push_back (EditableListColumn(_("Address")));
924 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
925 _cc = new EditableList<string, EmailDialog> (
928 bind (&Config::kdm_cc, Config::instance()),
929 bind (&Config::set_kdm_cc, Config::instance(), _1),
933 table->Add (_cc, 1, wxEXPAND | wxALL);
935 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
936 _bcc = new wxTextCtrl (_panel, wxID_ANY);
937 table->Add (_bcc, 1, wxEXPAND | wxALL);
939 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
940 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
942 _reset_email = new Button (_panel, _("Reset to default subject and text"));
943 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
947 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
948 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
949 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
950 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
951 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
954 void config_changed () override
956 auto config = Config::instance ();
958 checked_set (_subject, config->kdm_subject ());
959 checked_set (_from, config->kdm_from ());
960 checked_set (_bcc, config->kdm_bcc ());
961 checked_set (_email, Config::instance()->kdm_email ());
964 void kdm_subject_changed ()
966 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
969 void kdm_from_changed ()
971 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
974 void kdm_bcc_changed ()
976 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
979 void kdm_email_changed ()
981 if (_email->GetValue().IsEmpty ()) {
982 /* Sometimes we get sent an erroneous notification that the email
983 is empty; I don't know why.
987 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
992 Config::instance()->reset_kdm_email ();
993 checked_set (_email, Config::instance()->kdm_email ());
996 wxTextCtrl* _subject;
998 EditableList<string, EmailDialog>* _cc;
1001 wxButton* _reset_email;
1005 class NotificationsPage : public Page
1008 NotificationsPage (wxSize panel_size, int border)
1009 #ifdef DCPOMATIC_OSX
1010 /* We have to force both width and height of this one */
1011 : Page (wxSize (panel_size.GetWidth(), 128), border)
1013 : Page (panel_size, border)
1017 wxString GetName () const override
1019 return _("Notifications");
1022 #ifdef DCPOMATIC_OSX
1023 wxBitmap GetLargeIcon () const override
1025 return wxBitmap(bitmap_path("notifications"), wxBITMAP_TYPE_PNG);
1030 void setup () override
1032 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1033 table->AddGrowableCol (1, 1);
1034 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1036 _enable_message_box = new CheckBox (_panel, _("Message box"));
1037 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1038 table->AddSpacer (0);
1040 _enable_email = new CheckBox (_panel, _("Email"));
1041 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1042 table->AddSpacer (0);
1044 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1045 _subject = new wxTextCtrl (_panel, wxID_ANY);
1046 table->Add (_subject, 1, wxEXPAND | wxALL);
1048 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1049 _from = new wxTextCtrl (_panel, wxID_ANY);
1050 table->Add (_from, 1, wxEXPAND | wxALL);
1052 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1053 _to = new wxTextCtrl (_panel, wxID_ANY);
1054 table->Add (_to, 1, wxEXPAND | wxALL);
1056 vector<EditableListColumn> columns;
1057 columns.push_back (EditableListColumn(_("Address")));
1058 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1059 _cc = new EditableList<string, EmailDialog> (
1062 bind (&Config::notification_cc, Config::instance()),
1063 bind (&Config::set_notification_cc, Config::instance(), _1),
1064 [] (string s, int) {
1067 table->Add (_cc, 1, wxEXPAND | wxALL);
1069 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1070 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1071 table->Add (_bcc, 1, wxEXPAND | wxALL);
1073 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1074 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1076 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1077 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1081 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1082 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1084 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1085 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1086 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1087 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1088 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1089 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1091 setup_sensitivity ();
1094 void setup_sensitivity ()
1096 bool const s = _enable_email->GetValue();
1097 _subject->Enable(s);
1103 _reset_email->Enable(s);
1106 void config_changed () override
1108 auto config = Config::instance ();
1110 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1111 checked_set (_enable_email, config->notification(Config::EMAIL));
1112 checked_set (_subject, config->notification_subject ());
1113 checked_set (_from, config->notification_from ());
1114 checked_set (_to, config->notification_to ());
1115 checked_set (_bcc, config->notification_bcc ());
1116 checked_set (_email, Config::instance()->notification_email ());
1118 setup_sensitivity ();
1121 void notification_subject_changed ()
1123 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1126 void notification_from_changed ()
1128 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1131 void notification_to_changed ()
1133 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1136 void notification_bcc_changed ()
1138 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1141 void notification_email_changed ()
1143 if (_email->GetValue().IsEmpty()) {
1144 /* Sometimes we get sent an erroneous notification that the email
1145 is empty; I don't know why.
1149 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1154 Config::instance()->reset_notification_email();
1155 checked_set (_email, Config::instance()->notification_email());
1158 void type_changed (wxCheckBox* b, Config::Notification n)
1160 Config::instance()->set_notification(n, b->GetValue());
1161 setup_sensitivity ();
1164 wxCheckBox* _enable_message_box;
1165 wxCheckBox* _enable_email;
1167 wxTextCtrl* _subject;
1170 EditableList<string, EmailDialog>* _cc;
1173 wxButton* _reset_email;
1177 class CoverSheetPage : public Page
1181 CoverSheetPage (wxSize panel_size, int border)
1182 #ifdef DCPOMATIC_OSX
1183 /* We have to force both width and height of this one */
1184 : Page (wxSize (panel_size.GetWidth(), 128), border)
1186 : Page (panel_size, border)
1190 wxString GetName () const override
1192 return _("Cover Sheet");
1195 #ifdef DCPOMATIC_OSX
1196 wxBitmap GetLargeIcon () const override
1198 return wxBitmap(bitmap_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1203 void setup () override
1205 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1206 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1208 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1209 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1211 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1212 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1215 void config_changed () override
1217 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1220 void cover_sheet_changed ()
1222 if (_cover_sheet->GetValue().IsEmpty ()) {
1223 /* Sometimes we get sent an erroneous notification that the cover sheet
1224 is empty; I don't know why.
1228 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1231 void reset_cover_sheet ()
1233 Config::instance()->reset_cover_sheet();
1234 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1237 wxTextCtrl* _cover_sheet;
1238 wxButton* _reset_cover_sheet;
1242 class IdentifiersPage : public Page
1245 IdentifiersPage (wxSize panel_size, int border)
1246 : Page (panel_size, border)
1249 wxString GetName () const override
1251 return _("Identifiers");
1254 #ifdef DCPOMATIC_OSX
1255 wxBitmap GetLargeIcon () const override
1257 return wxBitmap(bitmap_path("identifiers"), wxBITMAP_TYPE_PNG);
1262 void setup () override
1264 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1265 table->AddGrowableCol (1, 1);
1267 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1268 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1269 _issuer->SetToolTip (_("This will be written to the DCP's XML files as the <Issuer>. If it is blank, a default value mentioning DCP-o-matic will be used."));
1270 table->Add (_issuer, 1, wxALL | wxEXPAND);
1272 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1273 _creator = new wxTextCtrl (_panel, wxID_ANY);
1274 _creator->SetToolTip (_("This will be written to the DCP's XML files as the <Creator>. If it is blank, a default value mentioning DCP-o-matic will be used."));
1275 table->Add (_creator, 1, wxALL | wxEXPAND);
1277 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1278 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1279 _company_name->SetToolTip (_("This will be written to the DCP's MXF files as the 'company name'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1280 table->Add (_company_name, 1, wxALL | wxEXPAND);
1282 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1283 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1284 _product_name->SetToolTip (_("This will be written to the DCP's MXF files as the 'product name'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1285 table->Add (_product_name, 1, wxALL | wxEXPAND);
1287 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1288 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1289 _product_version->SetToolTip (_("This will be written to the DCP's MXF files as the 'product version'. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1290 table->Add (_product_version, 1, wxALL | wxEXPAND);
1292 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1293 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1294 _j2k_comment->SetToolTip (_("This will be written to the DCP's JPEG2000 data as a comment. If it is blank, a default value mentioning libdcp (an internal DCP-o-matic library) will be used."));
1295 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1297 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1299 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1300 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1301 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1302 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1303 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1304 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1307 void config_changed () override
1309 auto config = Config::instance ();
1310 checked_set (_issuer, config->dcp_issuer ());
1311 checked_set (_creator, config->dcp_creator ());
1312 checked_set (_company_name, config->dcp_company_name ());
1313 checked_set (_product_name, config->dcp_product_name ());
1314 checked_set (_product_version, config->dcp_product_version ());
1315 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1318 void issuer_changed ()
1320 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1323 void creator_changed ()
1325 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1328 void company_name_changed ()
1330 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1333 void product_name_changed ()
1335 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1338 void product_version_changed ()
1340 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1343 void j2k_comment_changed ()
1345 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1348 wxTextCtrl* _issuer;
1349 wxTextCtrl* _creator;
1350 wxTextCtrl* _company_name;
1351 wxTextCtrl* _product_name;
1352 wxTextCtrl* _product_version;
1353 wxTextCtrl* _j2k_comment;
1357 /** @class AdvancedPage
1358 * @brief Advanced page of the preferences dialog.
1360 class AdvancedPage : public Page
1363 AdvancedPage (wxSize panel_size, int border)
1364 : Page (panel_size, border)
1367 wxString GetName () const override
1369 return _("Advanced");
1372 #ifdef DCPOMATIC_OSX
1373 wxBitmap GetLargeIcon () const override
1375 return wxBitmap(bitmap_path("advanced"), wxBITMAP_TYPE_PNG);
1380 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1382 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1384 flags |= wxALIGN_RIGHT;
1387 wxStaticText* m = new StaticText (parent, text);
1388 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1391 void setup () override
1393 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1394 table->AddGrowableCol (1, 1);
1395 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1398 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1399 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1400 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1401 s->Add (_maximum_j2k_bandwidth, 1);
1402 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1406 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1407 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1408 table->Add (_video_display_mode);
1410 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1411 auto font = restart->GetFont();
1412 font.SetStyle (wxFONTSTYLE_ITALIC);
1413 font.SetPointSize (font.GetPointSize() - 1);
1414 restart->SetFont (font);
1415 table->AddSpacer (0);
1417 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1418 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1419 table->AddSpacer (0);
1421 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1422 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1423 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1424 restart->SetFont (font);
1426 _allow_96khz_audio = new CheckBox (_panel, _("Allow creation of DCPs with 96kHz audio"));
1427 table->Add (_allow_96khz_audio, 1, wxEXPAND | wxALL);
1428 table->AddSpacer (0);
1430 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1431 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1432 table->AddSpacer (0);
1434 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1435 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1436 table->AddSpacer (0);
1439 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1440 auto s = new wxBoxSizer (wxHORIZONTAL);
1441 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1442 s->Add (_frames_in_memory_multiplier, 1);
1447 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1448 #ifdef DCPOMATIC_OSX
1449 auto align = new wxBoxSizer (wxHORIZONTAL);
1450 align->Add (format, 0, wxTOP, 2);
1451 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1453 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1455 dcp::NameFormat::Map titles;
1456 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1457 dcp::NameFormat::Map examples;
1458 examples['t'] = "cpl";
1459 _dcp_metadata_filename_format = new NameFormatEditor (
1460 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1462 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1466 auto format = create_label (_panel, _("DCP asset filename format"), true);
1467 #ifdef DCPOMATIC_OSX
1468 auto align = new wxBoxSizer (wxHORIZONTAL);
1469 align->Add (format, 0, wxTOP, 2);
1470 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1472 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1474 dcp::NameFormat::Map titles;
1475 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1476 titles['r'] = wx_to_std (_("reel number"));
1477 titles['n'] = wx_to_std (_("number of reels"));
1478 titles['c'] = wx_to_std (_("content filename"));
1479 dcp::NameFormat::Map examples;
1480 examples['t'] = "j2c";
1481 examples['r'] = "1";
1482 examples['n'] = "4";
1483 examples['c'] = "myfile.mp4";
1484 _dcp_asset_filename_format = new NameFormatEditor (
1485 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1487 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1491 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1492 auto t = new wxFlexGridSizer (2);
1493 _log_general = new CheckBox (_panel, _("General"));
1494 t->Add (_log_general, 1, wxEXPAND | wxALL);
1495 _log_warning = new CheckBox (_panel, _("Warnings"));
1496 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1497 _log_error = new CheckBox (_panel, _("Errors"));
1498 t->Add (_log_error, 1, wxEXPAND | wxALL);
1499 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1500 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1501 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1502 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1503 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1504 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1505 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1506 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1507 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1508 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1509 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1510 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1511 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1512 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1513 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1514 table->Add (t, 0, wxALL, 6);
1517 #ifdef DCPOMATIC_WINDOWS
1518 _win32_console = new CheckBox (_panel, _("Open console window"));
1519 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1520 table->AddSpacer (0);
1523 _maximum_j2k_bandwidth->SetRange (1, 1000);
1524 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1525 _video_display_mode->Append (_("Simple (safer)"));
1526 #if wxCHECK_VERSION(3, 1, 0)
1527 _video_display_mode->Append (_("OpenGL (faster)"));
1529 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1530 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1531 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1532 _allow_96khz_audio->Bind (wxEVT_CHECKBOX, boost::bind(&AdvancedPage::allow_96khz_audio_changed, this));
1533 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1534 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1535 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1536 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1537 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1538 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1539 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1540 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1541 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1542 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1543 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1544 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1545 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1546 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1547 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1548 #ifdef DCPOMATIC_WINDOWS
1549 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1553 void config_changed () override
1555 auto config = Config::instance ();
1557 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1558 switch (config->video_view_type()) {
1559 case Config::VIDEO_VIEW_SIMPLE:
1560 checked_set (_video_display_mode, 0);
1562 case Config::VIDEO_VIEW_OPENGL:
1563 checked_set (_video_display_mode, 1);
1566 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1567 checked_set (_allow_any_container, config->allow_any_container ());
1568 checked_set (_allow_96khz_audio, config->allow_96khz_audio());
1569 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1570 checked_set (_only_servers_encode, config->only_servers_encode ());
1571 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1572 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1573 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1574 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1575 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1576 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1577 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1578 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1579 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1580 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1581 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1582 #ifdef DCPOMATIC_WINDOWS
1583 checked_set (_win32_console, config->win32_console());
1587 void maximum_j2k_bandwidth_changed ()
1589 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1592 void video_display_mode_changed ()
1594 if (_video_display_mode->GetSelection() == 0) {
1595 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1597 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1601 void frames_in_memory_multiplier_changed ()
1603 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1606 void allow_any_dcp_frame_rate_changed ()
1608 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1611 void allow_any_container_changed ()
1613 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1616 void allow_96khz_audio_changed ()
1618 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1621 void show_experimental_audio_processors_changed ()
1623 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1626 void only_servers_encode_changed ()
1628 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1631 void dcp_metadata_filename_format_changed ()
1633 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1636 void dcp_asset_filename_format_changed ()
1638 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1644 if (_log_general->GetValue ()) {
1645 types |= LogEntry::TYPE_GENERAL;
1647 if (_log_warning->GetValue ()) {
1648 types |= LogEntry::TYPE_WARNING;
1650 if (_log_error->GetValue ()) {
1651 types |= LogEntry::TYPE_ERROR;
1653 if (_log_timing->GetValue ()) {
1654 types |= LogEntry::TYPE_TIMING;
1656 if (_log_debug_threed->GetValue ()) {
1657 types |= LogEntry::TYPE_DEBUG_THREE_D;
1659 if (_log_debug_encode->GetValue ()) {
1660 types |= LogEntry::TYPE_DEBUG_ENCODE;
1662 if (_log_debug_email->GetValue ()) {
1663 types |= LogEntry::TYPE_DEBUG_EMAIL;
1665 if (_log_debug_video_view->GetValue()) {
1666 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1668 if (_log_debug_player->GetValue()) {
1669 types |= LogEntry::TYPE_DEBUG_PLAYER;
1671 if (_log_debug_audio_analysis->GetValue()) {
1672 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1674 Config::instance()->set_log_types (types);
1677 #ifdef DCPOMATIC_WINDOWS
1678 void win32_console_changed ()
1680 Config::instance()->set_win32_console(_win32_console->GetValue());
1684 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1685 wxChoice* _video_display_mode = nullptr;
1686 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1687 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1688 wxCheckBox* _allow_any_container = nullptr;
1689 wxCheckBox* _allow_96khz_audio = nullptr;
1690 wxCheckBox* _show_experimental_audio_processors = nullptr;
1691 wxCheckBox* _only_servers_encode = nullptr;
1692 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1693 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1694 wxCheckBox* _log_general = nullptr;
1695 wxCheckBox* _log_warning = nullptr;
1696 wxCheckBox* _log_error = nullptr;
1697 wxCheckBox* _log_timing = nullptr;
1698 wxCheckBox* _log_debug_threed = nullptr;
1699 wxCheckBox* _log_debug_encode = nullptr;
1700 wxCheckBox* _log_debug_email = nullptr;
1701 wxCheckBox* _log_debug_video_view = nullptr;
1702 wxCheckBox* _log_debug_player = nullptr;
1703 wxCheckBox* _log_debug_audio_analysis = nullptr;
1704 #ifdef DCPOMATIC_WINDOWS
1705 wxCheckBox* _win32_console = nullptr;
1710 wxPreferencesEditor*
1711 create_full_config_dialog ()
1713 auto e = new wxPreferencesEditor ();
1715 #ifdef DCPOMATIC_OSX
1716 /* Width that we force some of the config panels to be on OSX so that
1717 the containing window doesn't shrink too much when we select those panels.
1718 This is obviously an unpleasant hack.
1720 wxSize ps = wxSize (750, -1);
1721 int const border = 16;
1723 wxSize ps = wxSize (-1, -1);
1724 int const border = 8;
1727 e->AddPage (new FullGeneralPage (ps, border));
1728 e->AddPage (new SoundPage (ps, border));
1729 e->AddPage (new DefaultsPage (ps, border));
1730 e->AddPage (new EncodingServersPage(ps, border));
1731 e->AddPage (new KeysPage (ps, border));
1732 e->AddPage (new TMSPage (ps, border));
1733 e->AddPage (new EmailPage (ps, border));
1734 e->AddPage (new KDMEmailPage (ps, border));
1735 e->AddPage (new NotificationsPage (ps, border));
1736 e->AddPage (new CoverSheetPage (ps, border));
1737 e->AddPage (new IdentifiersPage (ps, border));
1738 e->AddPage (new AdvancedPage (ps, border));