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 <wx/filepicker.h>
59 #include <wx/preferences.h>
60 #include <wx/spinctrl.h>
61 #include <wx/stdpaths.h>
63 #include <boost/filesystem.hpp>
73 using std::shared_ptr;
77 using boost::optional;
78 #if BOOST_VERSION >= 106100
79 using namespace boost::placeholders;
81 using dcp::locale_convert;
84 class FullGeneralPage : public GeneralPage
87 FullGeneralPage (wxSize panel_size, int border)
88 : GeneralPage (panel_size, border)
92 void setup () override
94 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
95 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
98 add_language_controls (table, r);
100 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
101 _master_encoding_threads = new wxSpinCtrl (_panel);
102 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
105 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
106 _server_encoding_threads = new wxSpinCtrl (_panel);
107 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
110 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
111 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
112 table->Add (_config_file, wxGBPosition (r, 1));
115 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
116 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
117 table->Add (_cinemas_file, wxGBPosition (r, 1));
118 Button* export_cinemas = new Button (_panel, _("Export..."));
119 table->Add (export_cinemas, wxGBPosition (r, 2));
122 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
123 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
124 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
128 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
129 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
132 add_update_controls (table, r);
134 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
135 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
137 _master_encoding_threads->SetRange (1, 128);
138 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
139 _server_encoding_threads->SetRange (1, 128);
140 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
141 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
143 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
144 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
146 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
149 void config_changed () override
151 auto config = Config::instance ();
153 checked_set (_master_encoding_threads, config->master_encoding_threads ());
154 checked_set (_server_encoding_threads, config->server_encoding_threads ());
155 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
156 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
158 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
159 checked_set (_config_file, config->config_read_file());
160 checked_set (_cinemas_file, config->cinemas_file());
162 GeneralPage::config_changed ();
165 void export_cinemas_file ()
167 auto d = new wxFileDialog (
168 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
169 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
172 if (d->ShowModal () == wxID_OK) {
173 boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
178 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
179 void analyse_ebur128_changed ()
181 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
185 void automatic_audio_analysis_changed ()
187 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
190 void master_encoding_threads_changed ()
192 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
195 void server_encoding_threads_changed ()
197 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
200 void config_file_changed ()
202 auto config = Config::instance();
203 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
204 if (new_file == config->config_read_file()) {
207 bool copy_and_link = true;
208 if (boost::filesystem::exists(new_file)) {
209 auto d = new ConfigMoveDialog (_panel, new_file);
210 if (d->ShowModal() == wxID_OK) {
211 copy_and_link = false;
218 if (new_file != config->config_read_file()) {
219 config->copy_and_link (new_file);
222 config->link (new_file);
226 void cinemas_file_changed ()
228 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
231 wxSpinCtrl* _master_encoding_threads;
232 wxSpinCtrl* _server_encoding_threads;
233 FilePickerCtrl* _config_file;
234 FilePickerCtrl* _cinemas_file;
235 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
236 wxCheckBox* _analyse_ebur128;
238 wxCheckBox* _automatic_audio_analysis;
242 class DefaultsPage : public Page
245 DefaultsPage (wxSize panel_size, int border)
246 : Page (panel_size, border)
249 wxString GetName () const override
251 return _("Defaults");
255 wxBitmap GetLargeIcon () const override
257 return wxBitmap(bitmap_path("defaults"), wxBITMAP_TYPE_PNG);
262 void setup () override
264 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
265 table->AddGrowableCol (1, 1);
266 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
269 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
270 auto s = new wxBoxSizer (wxHORIZONTAL);
271 _still_length = new wxSpinCtrl (_panel);
272 s->Add (_still_length);
273 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
277 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
278 #ifdef DCPOMATIC_USE_OWN_PICKER
279 _directory = new DirPickerCtrl (_panel);
281 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
283 table->Add (_directory, 1, wxEXPAND);
285 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
286 _container = new wxChoice (_panel, wxID_ANY);
287 table->Add (_container);
289 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
290 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
291 table->Add (_dcp_content_type);
293 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
294 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
295 table->Add (_dcp_audio_channels);
298 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
299 auto s = new wxBoxSizer (wxHORIZONTAL);
300 _j2k_bandwidth = new wxSpinCtrl (_panel);
301 s->Add (_j2k_bandwidth);
302 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
307 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
308 auto s = new wxBoxSizer (wxHORIZONTAL);
309 _audio_delay = new wxSpinCtrl (_panel);
310 s->Add (_audio_delay);
311 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
315 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
316 _standard = new wxChoice (_panel, wxID_ANY);
317 table->Add (_standard);
319 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
320 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
322 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
323 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
325 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
326 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
328 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
329 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
331 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
332 #ifdef DCPOMATIC_USE_OWN_PICKER
333 _kdm_directory = new DirPickerCtrl (_panel);
335 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
337 table->Add (_kdm_directory, 1, wxEXPAND);
339 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
340 _kdm_type = new KDMChoice (_panel);
341 table->Add (_kdm_type, 1, wxEXPAND);
343 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
345 _still_length->SetRange (1, 3600);
346 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
348 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
349 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
350 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
352 _use_isdcf_name_by_default->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::use_isdcf_name_by_default_changed, this));
354 for (auto i: Ratio::containers()) {
355 _container->Append (std_to_wx(i->container_nickname()));
358 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
360 for (auto i: DCPContentType::all()) {
361 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
364 setup_audio_channels_choice (_dcp_audio_channels, 2);
366 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
367 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
369 _j2k_bandwidth->SetRange (50, 250);
370 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
372 _audio_delay->SetRange (-1000, 1000);
373 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
375 _standard->Append (_("SMPTE"));
376 _standard->Append (_("Interop"));
377 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
379 for (auto const& i: _enable_metadata) {
380 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
383 for (auto const& i: _metadata) {
384 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
388 void config_changed () override
390 auto config = Config::instance ();
392 auto containers = Ratio::containers ();
393 for (size_t i = 0; i < containers.size(); ++i) {
394 if (containers[i] == config->default_container()) {
395 _container->SetSelection (i);
399 auto const ct = DCPContentType::all ();
400 for (size_t i = 0; i < ct.size(); ++i) {
401 if (ct[i] == config->default_dcp_content_type()) {
402 _dcp_content_type->SetSelection (i);
406 checked_set (_still_length, config->default_still_length ());
407 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
408 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
409 _kdm_type->set (config->default_kdm_type());
410 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
411 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
412 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
413 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
414 checked_set (_audio_delay, config->default_audio_delay ());
415 checked_set (_standard, config->default_interop() ? 1 : 0);
417 auto metadata = config->default_metadata();
419 for (auto const& i: metadata) {
420 _enable_metadata[i.first]->SetValue(true);
421 checked_set (_metadata[i.first], i.second);
424 for (auto const& i: _enable_metadata) {
425 if (metadata.find(i.first) == metadata.end()) {
426 checked_set (i.second, false);
430 for (auto const& i: _metadata) {
431 if (metadata.find(i.first) == metadata.end()) {
432 checked_set (i.second, wxT(""));
436 setup_sensitivity ();
439 void j2k_bandwidth_changed ()
441 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
444 void audio_delay_changed ()
446 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
449 void dcp_audio_channels_changed ()
451 int const s = _dcp_audio_channels->GetSelection ();
452 if (s != wxNOT_FOUND) {
453 Config::instance()->set_default_dcp_audio_channels (
454 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
459 void directory_changed ()
461 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
464 void kdm_directory_changed ()
466 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
469 void kdm_type_changed ()
471 Config::instance()->set_default_kdm_type(_kdm_type->get());
474 void use_isdcf_name_by_default_changed ()
476 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
479 void still_length_changed ()
481 Config::instance()->set_default_still_length (_still_length->GetValue ());
484 void container_changed ()
486 auto ratio = Ratio::containers ();
487 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
490 void dcp_content_type_changed ()
492 auto ct = DCPContentType::all ();
493 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
496 void standard_changed ()
498 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
501 void metadata_changed ()
503 map<string, string> metadata;
504 for (auto const& i: _enable_metadata) {
505 if (i.second->GetValue()) {
506 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
509 Config::instance()->set_default_metadata (metadata);
510 setup_sensitivity ();
513 void setup_sensitivity ()
515 for (auto const& i: _enable_metadata) {
516 _metadata[i.first]->Enable(i.second->GetValue());
520 wxSpinCtrl* _j2k_bandwidth;
521 wxSpinCtrl* _audio_delay;
522 wxSpinCtrl* _still_length;
523 #ifdef DCPOMATIC_USE_OWN_PICKER
524 DirPickerCtrl* _directory;
525 DirPickerCtrl* _kdm_directory;
527 wxDirPickerCtrl* _directory;
528 wxDirPickerCtrl* _kdm_directory;
530 KDMChoice* _kdm_type;
531 wxCheckBox* _use_isdcf_name_by_default;
532 wxChoice* _container;
533 wxChoice* _dcp_content_type;
534 wxChoice* _dcp_audio_channels;
536 map<string, CheckBox*> _enable_metadata;
537 map<string, wxTextCtrl*> _metadata;
541 class EncodingServersPage : public Page
544 EncodingServersPage (wxSize panel_size, int border)
545 : Page (panel_size, border)
548 wxString GetName () const override
554 wxBitmap GetLargeIcon () const override
556 return wxBitmap(bitmap_path("servers"), wxBITMAP_TYPE_PNG);
561 void setup () override
563 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
564 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
566 vector<EditableListColumn> columns;
567 columns.push_back (EditableListColumn(_("IP address / host name")));
568 _servers_list = new EditableList<string, ServerDialog> (
571 boost::bind (&Config::servers, Config::instance()),
572 boost::bind (&Config::set_servers, Config::instance(), _1),
573 boost::bind (&EncodingServersPage::server_column, this, _1)
576 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
578 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
581 void config_changed () override
583 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
584 _servers_list->refresh ();
587 void use_any_servers_changed ()
589 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
592 string server_column (string s)
597 wxCheckBox* _use_any_servers;
598 EditableList<string, ServerDialog>* _servers_list;
602 class TMSPage : public Page
605 TMSPage (wxSize panel_size, int border)
606 : Page (panel_size, border)
609 wxString GetName () const override
615 wxBitmap GetLargeIcon () const override
617 return wxBitmap(bitmap_path("tms"), wxBITMAP_TYPE_PNG);
622 void setup () override
624 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
625 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
627 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
628 table->AddGrowableCol (1, 1);
629 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
631 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
632 _tms_protocol = new wxChoice (_panel, wxID_ANY);
633 table->Add (_tms_protocol, 1, wxEXPAND);
635 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
636 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
637 table->Add (_tms_ip, 1, wxEXPAND);
639 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
640 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
641 table->Add (_tms_path, 1, wxEXPAND);
643 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
644 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
645 table->Add (_tms_user, 1, wxEXPAND);
647 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
648 _tms_password = new PasswordEntry (_panel);
649 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
651 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
652 _tms_protocol->Append (_("FTP (for Dolby)"));
654 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
655 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
656 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
657 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
658 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
659 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
662 void config_changed () override
664 auto config = Config::instance ();
666 checked_set (_upload, config->upload_after_make_dcp());
667 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
668 checked_set (_tms_ip, config->tms_ip ());
669 checked_set (_tms_path, config->tms_path ());
670 checked_set (_tms_user, config->tms_user ());
671 checked_set (_tms_password, config->tms_password ());
674 void upload_changed ()
676 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
679 void tms_protocol_changed ()
681 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
684 void tms_ip_changed ()
686 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
689 void tms_path_changed ()
691 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
694 void tms_user_changed ()
696 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
699 void tms_password_changed ()
701 Config::instance()->set_tms_password (_tms_password->get());
705 wxChoice* _tms_protocol;
707 wxTextCtrl* _tms_path;
708 wxTextCtrl* _tms_user;
709 PasswordEntry* _tms_password;
713 class EmailPage : public Page
716 EmailPage (wxSize panel_size, int border)
717 : Page (panel_size, border)
720 wxString GetName () const override
726 wxBitmap GetLargeIcon () const override
728 return wxBitmap(bitmap_path("email"), wxBITMAP_TYPE_PNG);
733 void setup () override
735 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
736 table->AddGrowableCol (1, 1);
737 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
739 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
741 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
742 _server = new wxTextCtrl (_panel, wxID_ANY);
743 s->Add (_server, 1, wxEXPAND | wxALL);
744 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
745 _port = new wxSpinCtrl (_panel, wxID_ANY);
746 _port->SetRange (0, 65535);
748 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
749 _protocol = new wxChoice (_panel, wxID_ANY);
750 /* Make sure this matches the switches in config_changed and port_changed below */
751 _protocol->Append (_("Auto"));
752 _protocol->Append (_("Plain"));
753 _protocol->Append (_("STARTTLS"));
754 _protocol->Append (_("SSL"));
755 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
756 table->Add (s, 1, wxEXPAND | wxALL);
759 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
760 _user = new wxTextCtrl (_panel, wxID_ANY);
761 table->Add (_user, 1, wxEXPAND | wxALL);
763 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
764 _password = new PasswordEntry (_panel);
765 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
767 table->AddSpacer (0);
768 _send_test_email = new Button (_panel, _("Send test email..."));
769 table->Add (_send_test_email);
771 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
772 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
773 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
774 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
775 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
776 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
779 void config_changed () override
781 auto config = Config::instance ();
783 checked_set (_server, config->mail_server());
784 checked_set (_port, config->mail_port());
785 switch (config->mail_protocol()) {
786 case EmailProtocol::AUTO:
787 checked_set (_protocol, 0);
789 case EmailProtocol::PLAIN:
790 checked_set (_protocol, 1);
792 case EmailProtocol::STARTTLS:
793 checked_set (_protocol, 2);
795 case EmailProtocol::SSL:
796 checked_set (_protocol, 3);
799 checked_set (_user, config->mail_user());
800 checked_set (_password, config->mail_password());
803 void server_changed ()
805 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
810 Config::instance()->set_mail_port(_port->GetValue());
813 void protocol_changed ()
815 switch (_protocol->GetSelection()) {
817 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
820 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
823 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
826 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
833 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
836 void password_changed ()
838 Config::instance()->set_mail_password(_password->get());
841 void send_test_email_clicked ()
843 auto dialog = new SendTestEmailDialog(_panel);
844 auto result = dialog->ShowModal();
846 if (result == wxID_OK) {
848 wx_to_std(dialog->from()),
849 { wx_to_std(dialog->to()) },
850 wx_to_std(_("DCP-o-matic test email")),
851 wx_to_std(_("This is a test email from DCP-o-matic."))
853 auto config = Config::instance();
855 emailer.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
856 } catch (NetworkError& e) {
857 error_dialog (_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
859 } catch (std::exception& e) {
860 error_dialog (_panel, _("Test email sending failed."), std_to_wx(e.what()));
863 error_dialog (_panel, _("Test email sending failed."));
866 message_dialog (_panel, _("Test email sent."));
874 PasswordEntry* _password;
875 Button* _send_test_email;
879 class KDMEmailPage : public Page
883 KDMEmailPage (wxSize panel_size, int border)
885 /* We have to force both width and height of this one */
886 : Page (wxSize (panel_size.GetWidth(), 128), border)
888 : Page (panel_size, border)
892 wxString GetName () const override
894 return _("KDM Email");
898 wxBitmap GetLargeIcon () const override
900 return wxBitmap(bitmap_path("kdm_email"), wxBITMAP_TYPE_PNG);
905 void setup () override
907 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
908 table->AddGrowableCol (1, 1);
909 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
911 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
912 _subject = new wxTextCtrl (_panel, wxID_ANY);
913 table->Add (_subject, 1, wxEXPAND | wxALL);
915 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
916 _from = new wxTextCtrl (_panel, wxID_ANY);
917 table->Add (_from, 1, wxEXPAND | wxALL);
919 vector<EditableListColumn> columns;
920 columns.push_back (EditableListColumn(_("Address")));
921 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
922 _cc = new EditableList<string, EmailDialog> (
925 bind (&Config::kdm_cc, Config::instance()),
926 bind (&Config::set_kdm_cc, Config::instance(), _1),
930 table->Add (_cc, 1, wxEXPAND | wxALL);
932 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
933 _bcc = new wxTextCtrl (_panel, wxID_ANY);
934 table->Add (_bcc, 1, wxEXPAND | wxALL);
936 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
937 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
939 _reset_email = new Button (_panel, _("Reset to default subject and text"));
940 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
944 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
945 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
946 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
947 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
948 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
951 void config_changed () override
953 auto config = Config::instance ();
955 checked_set (_subject, config->kdm_subject ());
956 checked_set (_from, config->kdm_from ());
957 checked_set (_bcc, config->kdm_bcc ());
958 checked_set (_email, Config::instance()->kdm_email ());
961 void kdm_subject_changed ()
963 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
966 void kdm_from_changed ()
968 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
971 void kdm_bcc_changed ()
973 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
976 void kdm_email_changed ()
978 if (_email->GetValue().IsEmpty ()) {
979 /* Sometimes we get sent an erroneous notification that the email
980 is empty; I don't know why.
984 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
989 Config::instance()->reset_kdm_email ();
990 checked_set (_email, Config::instance()->kdm_email ());
993 wxTextCtrl* _subject;
995 EditableList<string, EmailDialog>* _cc;
998 wxButton* _reset_email;
1002 class NotificationsPage : public Page
1005 NotificationsPage (wxSize panel_size, int border)
1006 #ifdef DCPOMATIC_OSX
1007 /* We have to force both width and height of this one */
1008 : Page (wxSize (panel_size.GetWidth(), 128), border)
1010 : Page (panel_size, border)
1014 wxString GetName () const override
1016 return _("Notifications");
1019 #ifdef DCPOMATIC_OSX
1020 wxBitmap GetLargeIcon () const override
1022 return wxBitmap(bitmap_path("notifications"), wxBITMAP_TYPE_PNG);
1027 void setup () override
1029 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1030 table->AddGrowableCol (1, 1);
1031 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1033 _enable_message_box = new CheckBox (_panel, _("Message box"));
1034 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1035 table->AddSpacer (0);
1037 _enable_email = new CheckBox (_panel, _("Email"));
1038 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1039 table->AddSpacer (0);
1041 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1042 _subject = new wxTextCtrl (_panel, wxID_ANY);
1043 table->Add (_subject, 1, wxEXPAND | wxALL);
1045 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1046 _from = new wxTextCtrl (_panel, wxID_ANY);
1047 table->Add (_from, 1, wxEXPAND | wxALL);
1049 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1050 _to = new wxTextCtrl (_panel, wxID_ANY);
1051 table->Add (_to, 1, wxEXPAND | wxALL);
1053 vector<EditableListColumn> columns;
1054 columns.push_back (EditableListColumn(_("Address")));
1055 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1056 _cc = new EditableList<string, EmailDialog> (
1059 bind (&Config::notification_cc, Config::instance()),
1060 bind (&Config::set_notification_cc, Config::instance(), _1),
1061 [] (string s, int) {
1064 table->Add (_cc, 1, wxEXPAND | wxALL);
1066 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1067 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1068 table->Add (_bcc, 1, wxEXPAND | wxALL);
1070 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1071 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1073 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1074 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1078 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1079 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1081 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1082 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1083 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1084 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1085 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1086 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1088 setup_sensitivity ();
1091 void setup_sensitivity ()
1093 bool const s = _enable_email->GetValue();
1094 _subject->Enable(s);
1100 _reset_email->Enable(s);
1103 void config_changed () override
1105 auto config = Config::instance ();
1107 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1108 checked_set (_enable_email, config->notification(Config::EMAIL));
1109 checked_set (_subject, config->notification_subject ());
1110 checked_set (_from, config->notification_from ());
1111 checked_set (_to, config->notification_to ());
1112 checked_set (_bcc, config->notification_bcc ());
1113 checked_set (_email, Config::instance()->notification_email ());
1115 setup_sensitivity ();
1118 void notification_subject_changed ()
1120 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1123 void notification_from_changed ()
1125 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1128 void notification_to_changed ()
1130 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1133 void notification_bcc_changed ()
1135 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1138 void notification_email_changed ()
1140 if (_email->GetValue().IsEmpty()) {
1141 /* Sometimes we get sent an erroneous notification that the email
1142 is empty; I don't know why.
1146 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1151 Config::instance()->reset_notification_email();
1152 checked_set (_email, Config::instance()->notification_email());
1155 void type_changed (wxCheckBox* b, Config::Notification n)
1157 Config::instance()->set_notification(n, b->GetValue());
1158 setup_sensitivity ();
1161 wxCheckBox* _enable_message_box;
1162 wxCheckBox* _enable_email;
1164 wxTextCtrl* _subject;
1167 EditableList<string, EmailDialog>* _cc;
1170 wxButton* _reset_email;
1174 class CoverSheetPage : public Page
1178 CoverSheetPage (wxSize panel_size, int border)
1179 #ifdef DCPOMATIC_OSX
1180 /* We have to force both width and height of this one */
1181 : Page (wxSize (panel_size.GetWidth(), 128), border)
1183 : Page (panel_size, border)
1187 wxString GetName () const override
1189 return _("Cover Sheet");
1192 #ifdef DCPOMATIC_OSX
1193 wxBitmap GetLargeIcon () const override
1195 return wxBitmap(bitmap_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1200 void setup () override
1202 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1203 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1205 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1206 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1208 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1209 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1212 void config_changed () override
1214 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1217 void cover_sheet_changed ()
1219 if (_cover_sheet->GetValue().IsEmpty ()) {
1220 /* Sometimes we get sent an erroneous notification that the cover sheet
1221 is empty; I don't know why.
1225 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1228 void reset_cover_sheet ()
1230 Config::instance()->reset_cover_sheet();
1231 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1234 wxTextCtrl* _cover_sheet;
1235 wxButton* _reset_cover_sheet;
1239 class IdentifiersPage : public Page
1242 IdentifiersPage (wxSize panel_size, int border)
1243 : Page (panel_size, border)
1246 wxString GetName () const override
1248 return _("Identifiers");
1251 #ifdef DCPOMATIC_OSX
1252 wxBitmap GetLargeIcon () const override
1254 return wxBitmap(bitmap_path("identifiers"), wxBITMAP_TYPE_PNG);
1259 void setup () override
1261 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1262 table->AddGrowableCol (1, 1);
1264 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1265 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1266 _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."));
1267 table->Add (_issuer, 1, wxALL | wxEXPAND);
1269 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1270 _creator = new wxTextCtrl (_panel, wxID_ANY);
1271 _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."));
1272 table->Add (_creator, 1, wxALL | wxEXPAND);
1274 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1275 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1276 _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."));
1277 table->Add (_company_name, 1, wxALL | wxEXPAND);
1279 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1280 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1281 _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."));
1282 table->Add (_product_name, 1, wxALL | wxEXPAND);
1284 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1285 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1286 _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."));
1287 table->Add (_product_version, 1, wxALL | wxEXPAND);
1289 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1290 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1291 _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."));
1292 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1294 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1296 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1297 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1298 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1299 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1300 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1301 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1304 void config_changed () override
1306 auto config = Config::instance ();
1307 checked_set (_issuer, config->dcp_issuer ());
1308 checked_set (_creator, config->dcp_creator ());
1309 checked_set (_company_name, config->dcp_company_name ());
1310 checked_set (_product_name, config->dcp_product_name ());
1311 checked_set (_product_version, config->dcp_product_version ());
1312 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1315 void issuer_changed ()
1317 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1320 void creator_changed ()
1322 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1325 void company_name_changed ()
1327 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1330 void product_name_changed ()
1332 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1335 void product_version_changed ()
1337 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1340 void j2k_comment_changed ()
1342 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1345 wxTextCtrl* _issuer;
1346 wxTextCtrl* _creator;
1347 wxTextCtrl* _company_name;
1348 wxTextCtrl* _product_name;
1349 wxTextCtrl* _product_version;
1350 wxTextCtrl* _j2k_comment;
1354 /** @class AdvancedPage
1355 * @brief Advanced page of the preferences dialog.
1357 class AdvancedPage : public Page
1360 AdvancedPage (wxSize panel_size, int border)
1361 : Page (panel_size, border)
1364 wxString GetName () const override
1366 return _("Advanced");
1369 #ifdef DCPOMATIC_OSX
1370 wxBitmap GetLargeIcon () const override
1372 return wxBitmap(bitmap_path("advanced"), wxBITMAP_TYPE_PNG);
1377 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1379 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1381 flags |= wxALIGN_RIGHT;
1384 wxStaticText* m = new StaticText (parent, text);
1385 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1388 void setup () override
1390 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1391 table->AddGrowableCol (1, 1);
1392 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1395 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1396 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1397 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1398 s->Add (_maximum_j2k_bandwidth, 1);
1399 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1403 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1404 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1405 table->Add (_video_display_mode);
1407 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1408 auto font = restart->GetFont();
1409 font.SetStyle (wxFONTSTYLE_ITALIC);
1410 font.SetPointSize (font.GetPointSize() - 1);
1411 restart->SetFont (font);
1412 table->AddSpacer (0);
1414 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1415 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1416 table->AddSpacer (0);
1418 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1419 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1420 table->AddSpacer (0);
1422 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1423 restart->SetFont (font);
1424 table->AddSpacer (0);
1426 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1427 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1428 table->AddSpacer (0);
1430 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1431 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1432 table->AddSpacer (0);
1435 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1436 auto s = new wxBoxSizer (wxHORIZONTAL);
1437 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1438 s->Add (_frames_in_memory_multiplier, 1);
1443 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1444 #ifdef DCPOMATIC_OSX
1445 auto align = new wxBoxSizer (wxHORIZONTAL);
1446 align->Add (format, 0, wxTOP, 2);
1447 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1449 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1451 dcp::NameFormat::Map titles;
1452 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1453 dcp::NameFormat::Map examples;
1454 examples['t'] = "cpl";
1455 _dcp_metadata_filename_format = new NameFormatEditor (
1456 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1458 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1462 auto format = create_label (_panel, _("DCP asset filename format"), true);
1463 #ifdef DCPOMATIC_OSX
1464 auto align = new wxBoxSizer (wxHORIZONTAL);
1465 align->Add (format, 0, wxTOP, 2);
1466 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1468 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1470 dcp::NameFormat::Map titles;
1471 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1472 titles['r'] = wx_to_std (_("reel number"));
1473 titles['n'] = wx_to_std (_("number of reels"));
1474 titles['c'] = wx_to_std (_("content filename"));
1475 dcp::NameFormat::Map examples;
1476 examples['t'] = "j2c";
1477 examples['r'] = "1";
1478 examples['n'] = "4";
1479 examples['c'] = "myfile.mp4";
1480 _dcp_asset_filename_format = new NameFormatEditor (
1481 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1483 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1487 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1488 auto t = new wxFlexGridSizer (2);
1489 _log_general = new CheckBox (_panel, _("General"));
1490 t->Add (_log_general, 1, wxEXPAND | wxALL);
1491 _log_warning = new CheckBox (_panel, _("Warnings"));
1492 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1493 _log_error = new CheckBox (_panel, _("Errors"));
1494 t->Add (_log_error, 1, wxEXPAND | wxALL);
1495 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1496 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1497 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1498 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1499 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1500 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1501 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1502 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1503 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1504 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1505 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1506 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1507 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1508 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1509 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1510 table->Add (t, 0, wxALL, 6);
1513 #ifdef DCPOMATIC_WINDOWS
1514 _win32_console = new CheckBox (_panel, _("Open console window"));
1515 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1516 table->AddSpacer (0);
1519 _maximum_j2k_bandwidth->SetRange (1, 1000);
1520 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1521 _video_display_mode->Append (_("Simple (safer)"));
1522 #if wxCHECK_VERSION(3, 1, 0)
1523 _video_display_mode->Append (_("OpenGL (faster)"));
1525 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1526 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1527 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1528 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1529 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1530 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1531 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1532 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1533 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1534 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1535 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1536 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1537 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1538 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1539 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1540 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1541 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1542 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1543 #ifdef DCPOMATIC_WINDOWS
1544 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1548 void config_changed () override
1550 auto config = Config::instance ();
1552 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1553 switch (config->video_view_type()) {
1554 case Config::VIDEO_VIEW_SIMPLE:
1555 checked_set (_video_display_mode, 0);
1557 case Config::VIDEO_VIEW_OPENGL:
1558 checked_set (_video_display_mode, 1);
1561 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1562 checked_set (_allow_any_container, config->allow_any_container ());
1563 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1564 checked_set (_only_servers_encode, config->only_servers_encode ());
1565 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1566 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1567 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1568 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1569 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1570 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1571 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1572 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1573 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1574 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1575 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1576 #ifdef DCPOMATIC_WINDOWS
1577 checked_set (_win32_console, config->win32_console());
1581 void maximum_j2k_bandwidth_changed ()
1583 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1586 void video_display_mode_changed ()
1588 if (_video_display_mode->GetSelection() == 0) {
1589 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1591 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1595 void frames_in_memory_multiplier_changed ()
1597 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1600 void allow_any_dcp_frame_rate_changed ()
1602 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1605 void allow_any_container_changed ()
1607 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1610 void show_experimental_audio_processors_changed ()
1612 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1615 void only_servers_encode_changed ()
1617 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1620 void dcp_metadata_filename_format_changed ()
1622 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1625 void dcp_asset_filename_format_changed ()
1627 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1633 if (_log_general->GetValue ()) {
1634 types |= LogEntry::TYPE_GENERAL;
1636 if (_log_warning->GetValue ()) {
1637 types |= LogEntry::TYPE_WARNING;
1639 if (_log_error->GetValue ()) {
1640 types |= LogEntry::TYPE_ERROR;
1642 if (_log_timing->GetValue ()) {
1643 types |= LogEntry::TYPE_TIMING;
1645 if (_log_debug_threed->GetValue ()) {
1646 types |= LogEntry::TYPE_DEBUG_THREE_D;
1648 if (_log_debug_encode->GetValue ()) {
1649 types |= LogEntry::TYPE_DEBUG_ENCODE;
1651 if (_log_debug_email->GetValue ()) {
1652 types |= LogEntry::TYPE_DEBUG_EMAIL;
1654 if (_log_debug_video_view->GetValue()) {
1655 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1657 if (_log_debug_player->GetValue()) {
1658 types |= LogEntry::TYPE_DEBUG_PLAYER;
1660 if (_log_debug_audio_analysis->GetValue()) {
1661 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1663 Config::instance()->set_log_types (types);
1666 #ifdef DCPOMATIC_WINDOWS
1667 void win32_console_changed ()
1669 Config::instance()->set_win32_console(_win32_console->GetValue());
1673 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1674 wxChoice* _video_display_mode = nullptr;
1675 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1676 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1677 wxCheckBox* _allow_any_container = nullptr;
1678 wxCheckBox* _show_experimental_audio_processors = nullptr;
1679 wxCheckBox* _only_servers_encode = nullptr;
1680 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1681 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1682 wxCheckBox* _log_general = nullptr;
1683 wxCheckBox* _log_warning = nullptr;
1684 wxCheckBox* _log_error = nullptr;
1685 wxCheckBox* _log_timing = nullptr;
1686 wxCheckBox* _log_debug_threed = nullptr;
1687 wxCheckBox* _log_debug_encode = nullptr;
1688 wxCheckBox* _log_debug_email = nullptr;
1689 wxCheckBox* _log_debug_video_view = nullptr;
1690 wxCheckBox* _log_debug_player = nullptr;
1691 wxCheckBox* _log_debug_audio_analysis = nullptr;
1692 #ifdef DCPOMATIC_WINDOWS
1693 wxCheckBox* _win32_console = nullptr;
1698 wxPreferencesEditor*
1699 create_full_config_dialog ()
1701 auto e = new wxPreferencesEditor ();
1703 #ifdef DCPOMATIC_OSX
1704 /* Width that we force some of the config panels to be on OSX so that
1705 the containing window doesn't shrink too much when we select those panels.
1706 This is obviously an unpleasant hack.
1708 wxSize ps = wxSize (750, -1);
1709 int const border = 16;
1711 wxSize ps = wxSize (-1, -1);
1712 int const border = 8;
1715 e->AddPage (new FullGeneralPage (ps, border));
1716 e->AddPage (new SoundPage (ps, border));
1717 e->AddPage (new DefaultsPage (ps, border));
1718 e->AddPage (new EncodingServersPage(ps, border));
1719 e->AddPage (new KeysPage (ps, border));
1720 e->AddPage (new TMSPage (ps, border));
1721 e->AddPage (new EmailPage (ps, border));
1722 e->AddPage (new KDMEmailPage (ps, border));
1723 e->AddPage (new NotificationsPage (ps, border));
1724 e->AddPage (new CoverSheetPage (ps, border));
1725 e->AddPage (new IdentifiersPage (ps, border));
1726 e->AddPage (new AdvancedPage (ps, border));