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 "make_chain_dialog.h"
38 #include "nag_dialog.h"
39 #include "name_format_editor.h"
40 #include "password_entry.h"
41 #include "server_dialog.h"
42 #include "static_text.h"
44 #include "lib/config.h"
45 #include "lib/cross.h"
46 #include "lib/dcp_content_type.h"
47 #include "lib/exceptions.h"
48 #include "lib/filter.h"
50 #include "lib/ratio.h"
52 #include <dcp/certificate_chain.h>
53 #include <dcp/exceptions.h>
54 #include <dcp/locale_convert.h>
55 #include <wx/filepicker.h>
56 #include <wx/preferences.h>
57 #include <wx/spinctrl.h>
58 #include <wx/stdpaths.h>
60 #include <boost/filesystem.hpp>
70 using std::shared_ptr;
74 using boost::optional;
75 #if BOOST_VERSION >= 106100
76 using namespace boost::placeholders;
78 using dcp::locale_convert;
81 class FullGeneralPage : public GeneralPage
84 FullGeneralPage (wxSize panel_size, int border)
85 : GeneralPage (panel_size, border)
91 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
92 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
95 add_language_controls (table, r);
97 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
98 _master_encoding_threads = new wxSpinCtrl (_panel);
99 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
102 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
103 _server_encoding_threads = new wxSpinCtrl (_panel);
104 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
107 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
108 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
109 table->Add (_config_file, wxGBPosition (r, 1));
112 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
113 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
114 table->Add (_cinemas_file, wxGBPosition (r, 1));
115 Button* export_cinemas = new Button (_panel, _("Export..."));
116 table->Add (export_cinemas, wxGBPosition (r, 2));
119 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
120 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
121 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
125 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
126 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
129 add_update_controls (table, r);
131 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
132 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
134 _master_encoding_threads->SetRange (1, 128);
135 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
136 _server_encoding_threads->SetRange (1, 128);
137 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
138 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
140 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
141 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
143 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
146 void config_changed ()
148 auto config = Config::instance ();
150 checked_set (_master_encoding_threads, config->master_encoding_threads ());
151 checked_set (_server_encoding_threads, config->server_encoding_threads ());
152 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
153 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
155 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
156 checked_set (_config_file, config->config_read_file());
157 checked_set (_cinemas_file, config->cinemas_file());
159 GeneralPage::config_changed ();
162 void export_cinemas_file ()
164 auto d = new wxFileDialog (
165 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
166 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
169 if (d->ShowModal () == wxID_OK) {
170 boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
175 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
176 void analyse_ebur128_changed ()
178 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
182 void automatic_audio_analysis_changed ()
184 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
187 void master_encoding_threads_changed ()
189 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
192 void server_encoding_threads_changed ()
194 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
197 void config_file_changed ()
199 auto config = Config::instance();
200 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
201 if (new_file == config->config_read_file()) {
204 bool copy_and_link = true;
205 if (boost::filesystem::exists(new_file)) {
206 auto d = new ConfigMoveDialog (_panel, new_file);
207 if (d->ShowModal() == wxID_OK) {
208 copy_and_link = false;
215 if (new_file != config->config_read_file()) {
216 config->copy_and_link (new_file);
219 config->link (new_file);
223 void cinemas_file_changed ()
225 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
228 wxSpinCtrl* _master_encoding_threads;
229 wxSpinCtrl* _server_encoding_threads;
230 FilePickerCtrl* _config_file;
231 FilePickerCtrl* _cinemas_file;
232 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
233 wxCheckBox* _analyse_ebur128;
235 wxCheckBox* _automatic_audio_analysis;
239 class DefaultsPage : public Page
242 DefaultsPage (wxSize panel_size, int border)
243 : Page (panel_size, border)
246 wxString GetName () const
248 return _("Defaults");
252 wxBitmap GetLargeIcon () const
254 return wxBitmap(bitmap_path("defaults"), wxBITMAP_TYPE_PNG);
261 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
262 table->AddGrowableCol (1, 1);
263 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
266 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
267 auto s = new wxBoxSizer (wxHORIZONTAL);
268 _still_length = new wxSpinCtrl (_panel);
269 s->Add (_still_length);
270 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
274 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
275 #ifdef DCPOMATIC_USE_OWN_PICKER
276 _directory = new DirPickerCtrl (_panel);
278 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
280 table->Add (_directory, 1, wxEXPAND);
282 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
283 _container = new wxChoice (_panel, wxID_ANY);
284 table->Add (_container);
286 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
287 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
288 table->Add (_dcp_content_type);
290 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
291 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
292 table->Add (_dcp_audio_channels);
295 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
296 auto s = new wxBoxSizer (wxHORIZONTAL);
297 _j2k_bandwidth = new wxSpinCtrl (_panel);
298 s->Add (_j2k_bandwidth);
299 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
304 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
305 auto s = new wxBoxSizer (wxHORIZONTAL);
306 _audio_delay = new wxSpinCtrl (_panel);
307 s->Add (_audio_delay);
308 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
312 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
313 _standard = new wxChoice (_panel, wxID_ANY);
314 table->Add (_standard);
316 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
317 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
319 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
320 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
322 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
323 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
325 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
326 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
328 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
329 #ifdef DCPOMATIC_USE_OWN_PICKER
330 _kdm_directory = new DirPickerCtrl (_panel);
332 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
335 table->Add (_kdm_directory, 1, wxEXPAND);
337 _still_length->SetRange (1, 3600);
338 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
340 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
341 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
343 for (auto i: Ratio::containers()) {
344 _container->Append (std_to_wx(i->container_nickname()));
347 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
349 for (auto i: DCPContentType::all()) {
350 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
353 setup_audio_channels_choice (_dcp_audio_channels, 2);
355 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
356 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
358 _j2k_bandwidth->SetRange (50, 250);
359 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
361 _audio_delay->SetRange (-1000, 1000);
362 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
364 _standard->Append (_("SMPTE"));
365 _standard->Append (_("Interop"));
366 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
368 for (auto const& i: _enable_metadata) {
369 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
372 for (auto const& i: _metadata) {
373 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
377 void config_changed ()
379 auto config = Config::instance ();
381 auto containers = Ratio::containers ();
382 for (size_t i = 0; i < containers.size(); ++i) {
383 if (containers[i] == config->default_container()) {
384 _container->SetSelection (i);
388 auto const ct = DCPContentType::all ();
389 for (size_t i = 0; i < ct.size(); ++i) {
390 if (ct[i] == config->default_dcp_content_type()) {
391 _dcp_content_type->SetSelection (i);
395 checked_set (_still_length, config->default_still_length ());
396 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
397 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
398 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
399 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
400 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
401 checked_set (_audio_delay, config->default_audio_delay ());
402 checked_set (_standard, config->default_interop() ? 1 : 0);
404 auto metadata = config->default_metadata();
406 for (auto const& i: metadata) {
407 _enable_metadata[i.first]->SetValue(true);
408 checked_set (_metadata[i.first], i.second);
411 for (auto const& i: _enable_metadata) {
412 if (metadata.find(i.first) == metadata.end()) {
413 checked_set (i.second, false);
417 for (auto const& i: _metadata) {
418 if (metadata.find(i.first) == metadata.end()) {
419 checked_set (i.second, wxT(""));
423 setup_sensitivity ();
426 void j2k_bandwidth_changed ()
428 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
431 void audio_delay_changed ()
433 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
436 void dcp_audio_channels_changed ()
438 int const s = _dcp_audio_channels->GetSelection ();
439 if (s != wxNOT_FOUND) {
440 Config::instance()->set_default_dcp_audio_channels (
441 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
446 void directory_changed ()
448 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
451 void kdm_directory_changed ()
453 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
456 void still_length_changed ()
458 Config::instance()->set_default_still_length (_still_length->GetValue ());
461 void container_changed ()
463 auto ratio = Ratio::containers ();
464 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
467 void dcp_content_type_changed ()
469 auto ct = DCPContentType::all ();
470 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
473 void standard_changed ()
475 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
478 void metadata_changed ()
480 map<string, string> metadata;
481 for (auto const& i: _enable_metadata) {
482 if (i.second->GetValue()) {
483 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
486 Config::instance()->set_default_metadata (metadata);
487 setup_sensitivity ();
490 void setup_sensitivity ()
492 for (auto const& i: _enable_metadata) {
493 _metadata[i.first]->Enable(i.second->GetValue());
497 wxSpinCtrl* _j2k_bandwidth;
498 wxSpinCtrl* _audio_delay;
499 wxSpinCtrl* _still_length;
500 #ifdef DCPOMATIC_USE_OWN_PICKER
501 DirPickerCtrl* _directory;
502 DirPickerCtrl* _kdm_directory;
504 wxDirPickerCtrl* _directory;
505 wxDirPickerCtrl* _kdm_directory;
507 wxChoice* _container;
508 wxChoice* _dcp_content_type;
509 wxChoice* _dcp_audio_channels;
511 map<string, CheckBox*> _enable_metadata;
512 map<string, wxTextCtrl*> _metadata;
516 class EncodingServersPage : public Page
519 EncodingServersPage (wxSize panel_size, int border)
520 : Page (panel_size, border)
523 wxString GetName () const
529 wxBitmap GetLargeIcon () const
531 return wxBitmap(bitmap_path("servers"), wxBITMAP_TYPE_PNG);
538 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
539 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
541 vector<EditableListColumn> columns;
542 columns.push_back (EditableListColumn(_("IP address / host name")));
543 _servers_list = new EditableList<string, ServerDialog> (
546 boost::bind (&Config::servers, Config::instance()),
547 boost::bind (&Config::set_servers, Config::instance(), _1),
548 boost::bind (&EncodingServersPage::server_column, this, _1)
551 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
553 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
556 void config_changed ()
558 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
559 _servers_list->refresh ();
562 void use_any_servers_changed ()
564 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
567 string server_column (string s)
572 wxCheckBox* _use_any_servers;
573 EditableList<string, ServerDialog>* _servers_list;
577 class TMSPage : public Page
580 TMSPage (wxSize panel_size, int border)
581 : Page (panel_size, border)
584 wxString GetName () const
590 wxBitmap GetLargeIcon () const
592 return wxBitmap(bitmap_path("tms"), wxBITMAP_TYPE_PNG);
599 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
600 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
602 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
603 table->AddGrowableCol (1, 1);
604 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
606 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
607 _tms_protocol = new wxChoice (_panel, wxID_ANY);
608 table->Add (_tms_protocol, 1, wxEXPAND);
610 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
611 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
612 table->Add (_tms_ip, 1, wxEXPAND);
614 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
615 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
616 table->Add (_tms_path, 1, wxEXPAND);
618 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
619 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
620 table->Add (_tms_user, 1, wxEXPAND);
622 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
623 _tms_password = new PasswordEntry (_panel);
624 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
626 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
627 _tms_protocol->Append (_("FTP (for Dolby)"));
629 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
630 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
631 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
632 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
633 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
634 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
637 void config_changed ()
639 auto config = Config::instance ();
641 checked_set (_upload, config->upload_after_make_dcp());
642 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
643 checked_set (_tms_ip, config->tms_ip ());
644 checked_set (_tms_path, config->tms_path ());
645 checked_set (_tms_user, config->tms_user ());
646 checked_set (_tms_password, config->tms_password ());
649 void upload_changed ()
651 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
654 void tms_protocol_changed ()
656 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
659 void tms_ip_changed ()
661 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
664 void tms_path_changed ()
666 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
669 void tms_user_changed ()
671 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
674 void tms_password_changed ()
676 Config::instance()->set_tms_password (_tms_password->get());
680 wxChoice* _tms_protocol;
682 wxTextCtrl* _tms_path;
683 wxTextCtrl* _tms_user;
684 PasswordEntry* _tms_password;
688 class EmailPage : public Page
691 EmailPage (wxSize panel_size, int border)
692 : Page (panel_size, border)
695 wxString GetName () const
701 wxBitmap GetLargeIcon () const
703 return wxBitmap(bitmap_path("email"), wxBITMAP_TYPE_PNG);
710 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
711 table->AddGrowableCol (1, 1);
712 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
714 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
716 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
717 _server = new wxTextCtrl (_panel, wxID_ANY);
718 s->Add (_server, 1, wxEXPAND | wxALL);
719 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
720 _port = new wxSpinCtrl (_panel, wxID_ANY);
721 _port->SetRange (0, 65535);
723 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
724 _protocol = new wxChoice (_panel, wxID_ANY);
725 /* Make sure this matches the switches in config_changed and port_changed below */
726 _protocol->Append (_("Auto"));
727 _protocol->Append (_("Plain"));
728 _protocol->Append (_("STARTTLS"));
729 _protocol->Append (_("SSL"));
730 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
731 table->Add (s, 1, wxEXPAND | wxALL);
734 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
735 _user = new wxTextCtrl (_panel, wxID_ANY);
736 table->Add (_user, 1, wxEXPAND | wxALL);
738 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
739 _password = new PasswordEntry (_panel);
740 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
742 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
743 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
744 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
745 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
746 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
749 void config_changed ()
751 auto config = Config::instance ();
753 checked_set (_server, config->mail_server());
754 checked_set (_port, config->mail_port());
755 switch (config->mail_protocol()) {
756 case EmailProtocol::AUTO:
757 checked_set (_protocol, 0);
759 case EmailProtocol::PLAIN:
760 checked_set (_protocol, 1);
762 case EmailProtocol::STARTTLS:
763 checked_set (_protocol, 2);
765 case EmailProtocol::SSL:
766 checked_set (_protocol, 3);
769 checked_set (_user, config->mail_user());
770 checked_set (_password, config->mail_password());
773 void server_changed ()
775 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
780 Config::instance()->set_mail_port(_port->GetValue());
783 void protocol_changed ()
785 switch (_protocol->GetSelection()) {
787 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
790 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
793 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
796 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
803 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
806 void password_changed ()
808 Config::instance()->set_mail_password(_password->get());
815 PasswordEntry* _password;
819 class KDMEmailPage : public Page
823 KDMEmailPage (wxSize panel_size, int border)
825 /* We have to force both width and height of this one */
826 : Page (wxSize (panel_size.GetWidth(), 128), border)
828 : Page (panel_size, border)
832 wxString GetName () const
834 return _("KDM Email");
838 wxBitmap GetLargeIcon () const
840 return wxBitmap(bitmap_path("kdm_email"), wxBITMAP_TYPE_PNG);
847 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
848 table->AddGrowableCol (1, 1);
849 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
851 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
852 _subject = new wxTextCtrl (_panel, wxID_ANY);
853 table->Add (_subject, 1, wxEXPAND | wxALL);
855 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
856 _from = new wxTextCtrl (_panel, wxID_ANY);
857 table->Add (_from, 1, wxEXPAND | wxALL);
859 vector<EditableListColumn> columns;
860 columns.push_back (EditableListColumn(_("Address")));
861 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
862 _cc = new EditableList<string, EmailDialog> (
865 bind (&Config::kdm_cc, Config::instance()),
866 bind (&Config::set_kdm_cc, Config::instance(), _1),
870 table->Add (_cc, 1, wxEXPAND | wxALL);
872 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
873 _bcc = new wxTextCtrl (_panel, wxID_ANY);
874 table->Add (_bcc, 1, wxEXPAND | wxALL);
876 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
877 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
879 _reset_email = new Button (_panel, _("Reset to default subject and text"));
880 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
884 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
885 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
886 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
887 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
888 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
891 void config_changed ()
893 Config* config = Config::instance ();
895 checked_set (_subject, config->kdm_subject ());
896 checked_set (_from, config->kdm_from ());
897 checked_set (_bcc, config->kdm_bcc ());
898 checked_set (_email, Config::instance()->kdm_email ());
901 void kdm_subject_changed ()
903 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
906 void kdm_from_changed ()
908 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
911 void kdm_bcc_changed ()
913 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
916 void kdm_email_changed ()
918 if (_email->GetValue().IsEmpty ()) {
919 /* Sometimes we get sent an erroneous notification that the email
920 is empty; I don't know why.
924 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
929 Config::instance()->reset_kdm_email ();
930 checked_set (_email, Config::instance()->kdm_email ());
933 wxTextCtrl* _subject;
935 EditableList<string, EmailDialog>* _cc;
938 wxButton* _reset_email;
942 class NotificationsPage : public Page
945 NotificationsPage (wxSize panel_size, int border)
947 /* We have to force both width and height of this one */
948 : Page (wxSize (panel_size.GetWidth(), 128), border)
950 : Page (panel_size, border)
954 wxString GetName () const
956 return _("Notifications");
960 wxBitmap GetLargeIcon () const
962 return wxBitmap(bitmap_path("notifications"), wxBITMAP_TYPE_PNG);
969 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
970 table->AddGrowableCol (1, 1);
971 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
973 _enable_message_box = new CheckBox (_panel, _("Message box"));
974 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
975 table->AddSpacer (0);
977 _enable_email = new CheckBox (_panel, _("Email"));
978 table->Add (_enable_email, 1, wxEXPAND | wxALL);
979 table->AddSpacer (0);
981 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
982 _subject = new wxTextCtrl (_panel, wxID_ANY);
983 table->Add (_subject, 1, wxEXPAND | wxALL);
985 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
986 _from = new wxTextCtrl (_panel, wxID_ANY);
987 table->Add (_from, 1, wxEXPAND | wxALL);
989 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
990 _to = new wxTextCtrl (_panel, wxID_ANY);
991 table->Add (_to, 1, wxEXPAND | wxALL);
993 vector<EditableListColumn> columns;
994 columns.push_back (EditableListColumn(_("Address")));
995 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
996 _cc = new EditableList<string, EmailDialog> (
999 bind (&Config::notification_cc, Config::instance()),
1000 bind (&Config::set_notification_cc, Config::instance(), _1),
1001 [] (string s, int) {
1004 table->Add (_cc, 1, wxEXPAND | wxALL);
1006 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1007 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1008 table->Add (_bcc, 1, wxEXPAND | wxALL);
1010 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1011 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1013 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1014 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1018 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1019 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1021 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1022 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1023 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1024 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1025 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1026 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1028 setup_sensitivity ();
1031 void setup_sensitivity ()
1033 bool const s = _enable_email->GetValue();
1034 _subject->Enable(s);
1040 _reset_email->Enable(s);
1043 void config_changed ()
1045 auto config = Config::instance ();
1047 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1048 checked_set (_enable_email, config->notification(Config::EMAIL));
1049 checked_set (_subject, config->notification_subject ());
1050 checked_set (_from, config->notification_from ());
1051 checked_set (_to, config->notification_to ());
1052 checked_set (_bcc, config->notification_bcc ());
1053 checked_set (_email, Config::instance()->notification_email ());
1055 setup_sensitivity ();
1058 void notification_subject_changed ()
1060 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1063 void notification_from_changed ()
1065 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1068 void notification_to_changed ()
1070 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1073 void notification_bcc_changed ()
1075 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1078 void notification_email_changed ()
1080 if (_email->GetValue().IsEmpty()) {
1081 /* Sometimes we get sent an erroneous notification that the email
1082 is empty; I don't know why.
1086 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1091 Config::instance()->reset_notification_email();
1092 checked_set (_email, Config::instance()->notification_email());
1095 void type_changed (wxCheckBox* b, Config::Notification n)
1097 Config::instance()->set_notification(n, b->GetValue());
1098 setup_sensitivity ();
1101 wxCheckBox* _enable_message_box;
1102 wxCheckBox* _enable_email;
1104 wxTextCtrl* _subject;
1107 EditableList<string, EmailDialog>* _cc;
1110 wxButton* _reset_email;
1114 class CoverSheetPage : public Page
1118 CoverSheetPage (wxSize panel_size, int border)
1119 #ifdef DCPOMATIC_OSX
1120 /* We have to force both width and height of this one */
1121 : Page (wxSize (panel_size.GetWidth(), 128), border)
1123 : Page (panel_size, border)
1127 wxString GetName () const
1129 return _("Cover Sheet");
1132 #ifdef DCPOMATIC_OSX
1133 wxBitmap GetLargeIcon () const
1135 return wxBitmap(bitmap_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1142 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1143 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1145 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1146 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1148 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1149 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1152 void config_changed ()
1154 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1157 void cover_sheet_changed ()
1159 if (_cover_sheet->GetValue().IsEmpty ()) {
1160 /* Sometimes we get sent an erroneous notification that the cover sheet
1161 is empty; I don't know why.
1165 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1168 void reset_cover_sheet ()
1170 Config::instance()->reset_cover_sheet();
1171 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1174 wxTextCtrl* _cover_sheet;
1175 wxButton* _reset_cover_sheet;
1179 class IdentifiersPage : public Page
1182 IdentifiersPage (wxSize panel_size, int border)
1183 : Page (panel_size, border)
1186 wxString GetName () const
1188 return _("Identifiers");
1191 #ifdef DCPOMATIC_OSX
1192 wxBitmap GetLargeIcon () const
1194 return wxBitmap(bitmap_path("identifiers"), wxBITMAP_TYPE_PNG);
1201 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1202 table->AddGrowableCol (1, 1);
1204 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1205 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1206 _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."));
1207 table->Add (_issuer, 1, wxALL | wxEXPAND);
1209 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1210 _creator = new wxTextCtrl (_panel, wxID_ANY);
1211 _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."));
1212 table->Add (_creator, 1, wxALL | wxEXPAND);
1214 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1215 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1216 _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."));
1217 table->Add (_company_name, 1, wxALL | wxEXPAND);
1219 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1220 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1221 _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."));
1222 table->Add (_product_name, 1, wxALL | wxEXPAND);
1224 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1225 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1226 _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."));
1227 table->Add (_product_version, 1, wxALL | wxEXPAND);
1229 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1230 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1231 _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."));
1232 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1234 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1236 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1237 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1238 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1239 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1240 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1241 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1244 void config_changed ()
1246 auto config = Config::instance ();
1247 checked_set (_issuer, config->dcp_issuer ());
1248 checked_set (_creator, config->dcp_creator ());
1249 checked_set (_company_name, config->dcp_company_name ());
1250 checked_set (_product_name, config->dcp_product_name ());
1251 checked_set (_product_version, config->dcp_product_version ());
1252 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1255 void issuer_changed ()
1257 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1260 void creator_changed ()
1262 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1265 void company_name_changed ()
1267 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1270 void product_name_changed ()
1272 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1275 void product_version_changed ()
1277 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1280 void j2k_comment_changed ()
1282 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1285 wxTextCtrl* _issuer;
1286 wxTextCtrl* _creator;
1287 wxTextCtrl* _company_name;
1288 wxTextCtrl* _product_name;
1289 wxTextCtrl* _product_version;
1290 wxTextCtrl* _j2k_comment;
1294 /** @class AdvancedPage
1295 * @brief Advanced page of the preferences dialog.
1297 class AdvancedPage : public Page
1300 AdvancedPage (wxSize panel_size, int border)
1301 : Page (panel_size, border)
1304 wxString GetName () const
1306 return _("Advanced");
1309 #ifdef DCPOMATIC_OSX
1310 wxBitmap GetLargeIcon () const
1312 return wxBitmap(bitmap_path("advanced"), wxBITMAP_TYPE_PNG);
1317 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1319 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1321 flags |= wxALIGN_RIGHT;
1324 wxStaticText* m = new StaticText (parent, text);
1325 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1330 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1331 table->AddGrowableCol (1, 1);
1332 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1335 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1336 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1337 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1338 s->Add (_maximum_j2k_bandwidth, 1);
1339 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1343 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1344 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1345 table->Add (_video_display_mode);
1347 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1348 auto font = restart->GetFont();
1349 font.SetStyle (wxFONTSTYLE_ITALIC);
1350 font.SetPointSize (font.GetPointSize() - 1);
1351 restart->SetFont (font);
1352 table->AddSpacer (0);
1354 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1355 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1356 table->AddSpacer (0);
1358 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1359 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1360 table->AddSpacer (0);
1362 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1363 restart->SetFont (font);
1364 table->AddSpacer (0);
1366 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1367 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1368 table->AddSpacer (0);
1370 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1371 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1372 table->AddSpacer (0);
1375 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1376 auto s = new wxBoxSizer (wxHORIZONTAL);
1377 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1378 s->Add (_frames_in_memory_multiplier, 1);
1383 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1384 #ifdef DCPOMATIC_OSX
1385 auto align = new wxBoxSizer (wxHORIZONTAL);
1386 align->Add (format, 0, wxTOP, 2);
1387 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1389 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1391 dcp::NameFormat::Map titles;
1392 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1393 dcp::NameFormat::Map examples;
1394 examples['t'] = "cpl";
1395 _dcp_metadata_filename_format = new NameFormatEditor (
1396 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1398 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1402 auto format = create_label (_panel, _("DCP asset filename format"), true);
1403 #ifdef DCPOMATIC_OSX
1404 auto align = new wxBoxSizer (wxHORIZONTAL);
1405 align->Add (format, 0, wxTOP, 2);
1406 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1408 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1410 dcp::NameFormat::Map titles;
1411 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1412 titles['r'] = wx_to_std (_("reel number"));
1413 titles['n'] = wx_to_std (_("number of reels"));
1414 titles['c'] = wx_to_std (_("content filename"));
1415 dcp::NameFormat::Map examples;
1416 examples['t'] = "j2c";
1417 examples['r'] = "1";
1418 examples['n'] = "4";
1419 examples['c'] = "myfile.mp4";
1420 _dcp_asset_filename_format = new NameFormatEditor (
1421 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1423 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1427 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1428 auto t = new wxBoxSizer (wxVERTICAL);
1429 _log_general = new CheckBox (_panel, _("General"));
1430 t->Add (_log_general, 1, wxEXPAND | wxALL);
1431 _log_warning = new CheckBox (_panel, _("Warnings"));
1432 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1433 _log_error = new CheckBox (_panel, _("Errors"));
1434 t->Add (_log_error, 1, wxEXPAND | wxALL);
1435 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1436 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1437 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1438 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1439 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1440 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1441 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1442 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1443 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1444 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1445 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1446 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1447 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1448 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1449 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1450 table->Add (t, 0, wxALL, 6);
1453 #ifdef DCPOMATIC_WINDOWS
1454 _win32_console = new CheckBox (_panel, _("Open console window"));
1455 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1456 table->AddSpacer (0);
1459 _maximum_j2k_bandwidth->SetRange (1, 1000);
1460 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1461 _video_display_mode->Append (_("Simple (safer)"));
1462 _video_display_mode->Append (_("OpenGL (faster)"));
1463 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1464 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1465 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1466 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1467 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1468 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1469 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1470 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1471 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1472 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1473 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1474 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1475 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1476 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1477 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1478 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1479 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1480 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1481 #ifdef DCPOMATIC_WINDOWS
1482 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1486 void config_changed ()
1488 auto config = Config::instance ();
1490 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1491 switch (config->video_view_type()) {
1492 case Config::VIDEO_VIEW_SIMPLE:
1493 checked_set (_video_display_mode, 0);
1495 case Config::VIDEO_VIEW_OPENGL:
1496 checked_set (_video_display_mode, 1);
1499 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1500 checked_set (_allow_any_container, config->allow_any_container ());
1501 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1502 checked_set (_only_servers_encode, config->only_servers_encode ());
1503 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1504 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1505 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1506 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1507 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1508 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1509 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1510 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1511 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1512 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1513 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1514 #ifdef DCPOMATIC_WINDOWS
1515 checked_set (_win32_console, config->win32_console());
1519 void maximum_j2k_bandwidth_changed ()
1521 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1524 void video_display_mode_changed ()
1526 if (_video_display_mode->GetSelection() == 0) {
1527 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1529 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1533 void frames_in_memory_multiplier_changed ()
1535 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1538 void allow_any_dcp_frame_rate_changed ()
1540 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1543 void allow_any_container_changed ()
1545 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1548 void show_experimental_audio_processors_changed ()
1550 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1553 void only_servers_encode_changed ()
1555 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1558 void dcp_metadata_filename_format_changed ()
1560 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1563 void dcp_asset_filename_format_changed ()
1565 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1571 if (_log_general->GetValue ()) {
1572 types |= LogEntry::TYPE_GENERAL;
1574 if (_log_warning->GetValue ()) {
1575 types |= LogEntry::TYPE_WARNING;
1577 if (_log_error->GetValue ()) {
1578 types |= LogEntry::TYPE_ERROR;
1580 if (_log_timing->GetValue ()) {
1581 types |= LogEntry::TYPE_TIMING;
1583 if (_log_debug_threed->GetValue ()) {
1584 types |= LogEntry::TYPE_DEBUG_THREE_D;
1586 if (_log_debug_encode->GetValue ()) {
1587 types |= LogEntry::TYPE_DEBUG_ENCODE;
1589 if (_log_debug_email->GetValue ()) {
1590 types |= LogEntry::TYPE_DEBUG_EMAIL;
1592 if (_log_debug_video_view->GetValue()) {
1593 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1595 if (_log_debug_player->GetValue()) {
1596 types |= LogEntry::TYPE_DEBUG_PLAYER;
1598 if (_log_debug_audio_analysis->GetValue()) {
1599 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1601 Config::instance()->set_log_types (types);
1604 #ifdef DCPOMATIC_WINDOWS
1605 void win32_console_changed ()
1607 Config::instance()->set_win32_console(_win32_console->GetValue());
1611 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1612 wxChoice* _video_display_mode = nullptr;
1613 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1614 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1615 wxCheckBox* _allow_any_container = nullptr;
1616 wxCheckBox* _show_experimental_audio_processors = nullptr;
1617 wxCheckBox* _only_servers_encode = nullptr;
1618 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1619 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1620 wxCheckBox* _log_general = nullptr;
1621 wxCheckBox* _log_warning = nullptr;
1622 wxCheckBox* _log_error = nullptr;
1623 wxCheckBox* _log_timing = nullptr;
1624 wxCheckBox* _log_debug_threed = nullptr;
1625 wxCheckBox* _log_debug_encode = nullptr;
1626 wxCheckBox* _log_debug_email = nullptr;
1627 wxCheckBox* _log_debug_video_view = nullptr;
1628 wxCheckBox* _log_debug_player = nullptr;
1629 wxCheckBox* _log_debug_audio_analysis = nullptr;
1630 #ifdef DCPOMATIC_WINDOWS
1631 wxCheckBox* _win32_console = nullptr;
1636 wxPreferencesEditor*
1637 create_full_config_dialog ()
1639 auto e = new wxPreferencesEditor ();
1641 #ifdef DCPOMATIC_OSX
1642 /* Width that we force some of the config panels to be on OSX so that
1643 the containing window doesn't shrink too much when we select those panels.
1644 This is obviously an unpleasant hack.
1646 wxSize ps = wxSize (700, -1);
1647 int const border = 16;
1649 wxSize ps = wxSize (-1, -1);
1650 int const border = 8;
1653 e->AddPage (new FullGeneralPage (ps, border));
1654 e->AddPage (new SoundPage (ps, border));
1655 e->AddPage (new DefaultsPage (ps, border));
1656 e->AddPage (new EncodingServersPage(ps, border));
1657 e->AddPage (new KeysPage (ps, border));
1658 e->AddPage (new TMSPage (ps, border));
1659 e->AddPage (new EmailPage (ps, border));
1660 e->AddPage (new KDMEmailPage (ps, border));
1661 e->AddPage (new NotificationsPage (ps, border));
1662 e->AddPage (new CoverSheetPage (ps, border));
1663 e->AddPage (new IdentifiersPage (ps, border));
1664 e->AddPage (new AdvancedPage (ps, border));