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 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
339 _still_length->SetRange (1, 3600);
340 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
342 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
343 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
345 _use_isdcf_name_by_default->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::use_isdcf_name_by_default_changed, this));
347 for (auto i: Ratio::containers()) {
348 _container->Append (std_to_wx(i->container_nickname()));
351 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
353 for (auto i: DCPContentType::all()) {
354 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
357 setup_audio_channels_choice (_dcp_audio_channels, 2);
359 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
360 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
362 _j2k_bandwidth->SetRange (50, 250);
363 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
365 _audio_delay->SetRange (-1000, 1000);
366 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
368 _standard->Append (_("SMPTE"));
369 _standard->Append (_("Interop"));
370 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
372 for (auto const& i: _enable_metadata) {
373 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
376 for (auto const& i: _metadata) {
377 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
381 void config_changed ()
383 auto config = Config::instance ();
385 auto containers = Ratio::containers ();
386 for (size_t i = 0; i < containers.size(); ++i) {
387 if (containers[i] == config->default_container()) {
388 _container->SetSelection (i);
392 auto const ct = DCPContentType::all ();
393 for (size_t i = 0; i < ct.size(); ++i) {
394 if (ct[i] == config->default_dcp_content_type()) {
395 _dcp_content_type->SetSelection (i);
399 checked_set (_still_length, config->default_still_length ());
400 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
401 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
402 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
403 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
404 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
405 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
406 checked_set (_audio_delay, config->default_audio_delay ());
407 checked_set (_standard, config->default_interop() ? 1 : 0);
409 auto metadata = config->default_metadata();
411 for (auto const& i: metadata) {
412 _enable_metadata[i.first]->SetValue(true);
413 checked_set (_metadata[i.first], i.second);
416 for (auto const& i: _enable_metadata) {
417 if (metadata.find(i.first) == metadata.end()) {
418 checked_set (i.second, false);
422 for (auto const& i: _metadata) {
423 if (metadata.find(i.first) == metadata.end()) {
424 checked_set (i.second, wxT(""));
428 setup_sensitivity ();
431 void j2k_bandwidth_changed ()
433 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
436 void audio_delay_changed ()
438 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
441 void dcp_audio_channels_changed ()
443 int const s = _dcp_audio_channels->GetSelection ();
444 if (s != wxNOT_FOUND) {
445 Config::instance()->set_default_dcp_audio_channels (
446 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
451 void directory_changed ()
453 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
456 void kdm_directory_changed ()
458 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
461 void use_isdcf_name_by_default_changed ()
463 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
466 void still_length_changed ()
468 Config::instance()->set_default_still_length (_still_length->GetValue ());
471 void container_changed ()
473 auto ratio = Ratio::containers ();
474 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
477 void dcp_content_type_changed ()
479 auto ct = DCPContentType::all ();
480 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
483 void standard_changed ()
485 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
488 void metadata_changed ()
490 map<string, string> metadata;
491 for (auto const& i: _enable_metadata) {
492 if (i.second->GetValue()) {
493 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
496 Config::instance()->set_default_metadata (metadata);
497 setup_sensitivity ();
500 void setup_sensitivity ()
502 for (auto const& i: _enable_metadata) {
503 _metadata[i.first]->Enable(i.second->GetValue());
507 wxSpinCtrl* _j2k_bandwidth;
508 wxSpinCtrl* _audio_delay;
509 wxSpinCtrl* _still_length;
510 #ifdef DCPOMATIC_USE_OWN_PICKER
511 DirPickerCtrl* _directory;
512 DirPickerCtrl* _kdm_directory;
514 wxDirPickerCtrl* _directory;
515 wxDirPickerCtrl* _kdm_directory;
517 wxCheckBox* _use_isdcf_name_by_default;
518 wxChoice* _container;
519 wxChoice* _dcp_content_type;
520 wxChoice* _dcp_audio_channels;
522 map<string, CheckBox*> _enable_metadata;
523 map<string, wxTextCtrl*> _metadata;
527 class EncodingServersPage : public Page
530 EncodingServersPage (wxSize panel_size, int border)
531 : Page (panel_size, border)
534 wxString GetName () const
540 wxBitmap GetLargeIcon () const
542 return wxBitmap(bitmap_path("servers"), wxBITMAP_TYPE_PNG);
549 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
550 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
552 vector<EditableListColumn> columns;
553 columns.push_back (EditableListColumn(_("IP address / host name")));
554 _servers_list = new EditableList<string, ServerDialog> (
557 boost::bind (&Config::servers, Config::instance()),
558 boost::bind (&Config::set_servers, Config::instance(), _1),
559 boost::bind (&EncodingServersPage::server_column, this, _1)
562 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
564 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
567 void config_changed ()
569 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
570 _servers_list->refresh ();
573 void use_any_servers_changed ()
575 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
578 string server_column (string s)
583 wxCheckBox* _use_any_servers;
584 EditableList<string, ServerDialog>* _servers_list;
588 class TMSPage : public Page
591 TMSPage (wxSize panel_size, int border)
592 : Page (panel_size, border)
595 wxString GetName () const
601 wxBitmap GetLargeIcon () const
603 return wxBitmap(bitmap_path("tms"), wxBITMAP_TYPE_PNG);
610 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
611 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
613 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
614 table->AddGrowableCol (1, 1);
615 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
617 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
618 _tms_protocol = new wxChoice (_panel, wxID_ANY);
619 table->Add (_tms_protocol, 1, wxEXPAND);
621 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
622 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
623 table->Add (_tms_ip, 1, wxEXPAND);
625 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
626 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
627 table->Add (_tms_path, 1, wxEXPAND);
629 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
630 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
631 table->Add (_tms_user, 1, wxEXPAND);
633 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
634 _tms_password = new PasswordEntry (_panel);
635 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
637 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
638 _tms_protocol->Append (_("FTP (for Dolby)"));
640 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
641 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
642 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
643 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
644 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
645 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
648 void config_changed ()
650 auto config = Config::instance ();
652 checked_set (_upload, config->upload_after_make_dcp());
653 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
654 checked_set (_tms_ip, config->tms_ip ());
655 checked_set (_tms_path, config->tms_path ());
656 checked_set (_tms_user, config->tms_user ());
657 checked_set (_tms_password, config->tms_password ());
660 void upload_changed ()
662 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
665 void tms_protocol_changed ()
667 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
670 void tms_ip_changed ()
672 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
675 void tms_path_changed ()
677 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
680 void tms_user_changed ()
682 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
685 void tms_password_changed ()
687 Config::instance()->set_tms_password (_tms_password->get());
691 wxChoice* _tms_protocol;
693 wxTextCtrl* _tms_path;
694 wxTextCtrl* _tms_user;
695 PasswordEntry* _tms_password;
699 class EmailPage : public Page
702 EmailPage (wxSize panel_size, int border)
703 : Page (panel_size, border)
706 wxString GetName () const
712 wxBitmap GetLargeIcon () const
714 return wxBitmap(bitmap_path("email"), wxBITMAP_TYPE_PNG);
721 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
722 table->AddGrowableCol (1, 1);
723 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
725 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
727 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
728 _server = new wxTextCtrl (_panel, wxID_ANY);
729 s->Add (_server, 1, wxEXPAND | wxALL);
730 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
731 _port = new wxSpinCtrl (_panel, wxID_ANY);
732 _port->SetRange (0, 65535);
734 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
735 _protocol = new wxChoice (_panel, wxID_ANY);
736 /* Make sure this matches the switches in config_changed and port_changed below */
737 _protocol->Append (_("Auto"));
738 _protocol->Append (_("Plain"));
739 _protocol->Append (_("STARTTLS"));
740 _protocol->Append (_("SSL"));
741 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
742 table->Add (s, 1, wxEXPAND | wxALL);
745 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
746 _user = new wxTextCtrl (_panel, wxID_ANY);
747 table->Add (_user, 1, wxEXPAND | wxALL);
749 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
750 _password = new PasswordEntry (_panel);
751 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
753 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
754 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
755 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
756 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
757 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
760 void config_changed ()
762 auto config = Config::instance ();
764 checked_set (_server, config->mail_server());
765 checked_set (_port, config->mail_port());
766 switch (config->mail_protocol()) {
767 case EmailProtocol::AUTO:
768 checked_set (_protocol, 0);
770 case EmailProtocol::PLAIN:
771 checked_set (_protocol, 1);
773 case EmailProtocol::STARTTLS:
774 checked_set (_protocol, 2);
776 case EmailProtocol::SSL:
777 checked_set (_protocol, 3);
780 checked_set (_user, config->mail_user());
781 checked_set (_password, config->mail_password());
784 void server_changed ()
786 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
791 Config::instance()->set_mail_port(_port->GetValue());
794 void protocol_changed ()
796 switch (_protocol->GetSelection()) {
798 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
801 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
804 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
807 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
814 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
817 void password_changed ()
819 Config::instance()->set_mail_password(_password->get());
826 PasswordEntry* _password;
830 class KDMEmailPage : public Page
834 KDMEmailPage (wxSize panel_size, int border)
836 /* We have to force both width and height of this one */
837 : Page (wxSize (panel_size.GetWidth(), 128), border)
839 : Page (panel_size, border)
843 wxString GetName () const
845 return _("KDM Email");
849 wxBitmap GetLargeIcon () const
851 return wxBitmap(bitmap_path("kdm_email"), wxBITMAP_TYPE_PNG);
858 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
859 table->AddGrowableCol (1, 1);
860 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
862 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
863 _subject = new wxTextCtrl (_panel, wxID_ANY);
864 table->Add (_subject, 1, wxEXPAND | wxALL);
866 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
867 _from = new wxTextCtrl (_panel, wxID_ANY);
868 table->Add (_from, 1, wxEXPAND | wxALL);
870 vector<EditableListColumn> columns;
871 columns.push_back (EditableListColumn(_("Address")));
872 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
873 _cc = new EditableList<string, EmailDialog> (
876 bind (&Config::kdm_cc, Config::instance()),
877 bind (&Config::set_kdm_cc, Config::instance(), _1),
881 table->Add (_cc, 1, wxEXPAND | wxALL);
883 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
884 _bcc = new wxTextCtrl (_panel, wxID_ANY);
885 table->Add (_bcc, 1, wxEXPAND | wxALL);
887 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
888 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
890 _reset_email = new Button (_panel, _("Reset to default subject and text"));
891 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
895 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
896 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
897 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
898 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
899 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
902 void config_changed ()
904 Config* config = Config::instance ();
906 checked_set (_subject, config->kdm_subject ());
907 checked_set (_from, config->kdm_from ());
908 checked_set (_bcc, config->kdm_bcc ());
909 checked_set (_email, Config::instance()->kdm_email ());
912 void kdm_subject_changed ()
914 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
917 void kdm_from_changed ()
919 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
922 void kdm_bcc_changed ()
924 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
927 void kdm_email_changed ()
929 if (_email->GetValue().IsEmpty ()) {
930 /* Sometimes we get sent an erroneous notification that the email
931 is empty; I don't know why.
935 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
940 Config::instance()->reset_kdm_email ();
941 checked_set (_email, Config::instance()->kdm_email ());
944 wxTextCtrl* _subject;
946 EditableList<string, EmailDialog>* _cc;
949 wxButton* _reset_email;
953 class NotificationsPage : public Page
956 NotificationsPage (wxSize panel_size, int border)
958 /* We have to force both width and height of this one */
959 : Page (wxSize (panel_size.GetWidth(), 128), border)
961 : Page (panel_size, border)
965 wxString GetName () const
967 return _("Notifications");
971 wxBitmap GetLargeIcon () const
973 return wxBitmap(bitmap_path("notifications"), wxBITMAP_TYPE_PNG);
980 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
981 table->AddGrowableCol (1, 1);
982 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
984 _enable_message_box = new CheckBox (_panel, _("Message box"));
985 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
986 table->AddSpacer (0);
988 _enable_email = new CheckBox (_panel, _("Email"));
989 table->Add (_enable_email, 1, wxEXPAND | wxALL);
990 table->AddSpacer (0);
992 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
993 _subject = new wxTextCtrl (_panel, wxID_ANY);
994 table->Add (_subject, 1, wxEXPAND | wxALL);
996 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
997 _from = new wxTextCtrl (_panel, wxID_ANY);
998 table->Add (_from, 1, wxEXPAND | wxALL);
1000 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1001 _to = new wxTextCtrl (_panel, wxID_ANY);
1002 table->Add (_to, 1, wxEXPAND | wxALL);
1004 vector<EditableListColumn> columns;
1005 columns.push_back (EditableListColumn(_("Address")));
1006 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1007 _cc = new EditableList<string, EmailDialog> (
1010 bind (&Config::notification_cc, Config::instance()),
1011 bind (&Config::set_notification_cc, Config::instance(), _1),
1012 [] (string s, int) {
1015 table->Add (_cc, 1, wxEXPAND | wxALL);
1017 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1018 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1019 table->Add (_bcc, 1, wxEXPAND | wxALL);
1021 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1022 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1024 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1025 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1029 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1030 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1032 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1033 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1034 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1035 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1036 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1037 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1039 setup_sensitivity ();
1042 void setup_sensitivity ()
1044 bool const s = _enable_email->GetValue();
1045 _subject->Enable(s);
1051 _reset_email->Enable(s);
1054 void config_changed ()
1056 auto config = Config::instance ();
1058 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1059 checked_set (_enable_email, config->notification(Config::EMAIL));
1060 checked_set (_subject, config->notification_subject ());
1061 checked_set (_from, config->notification_from ());
1062 checked_set (_to, config->notification_to ());
1063 checked_set (_bcc, config->notification_bcc ());
1064 checked_set (_email, Config::instance()->notification_email ());
1066 setup_sensitivity ();
1069 void notification_subject_changed ()
1071 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1074 void notification_from_changed ()
1076 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1079 void notification_to_changed ()
1081 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1084 void notification_bcc_changed ()
1086 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1089 void notification_email_changed ()
1091 if (_email->GetValue().IsEmpty()) {
1092 /* Sometimes we get sent an erroneous notification that the email
1093 is empty; I don't know why.
1097 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1102 Config::instance()->reset_notification_email();
1103 checked_set (_email, Config::instance()->notification_email());
1106 void type_changed (wxCheckBox* b, Config::Notification n)
1108 Config::instance()->set_notification(n, b->GetValue());
1109 setup_sensitivity ();
1112 wxCheckBox* _enable_message_box;
1113 wxCheckBox* _enable_email;
1115 wxTextCtrl* _subject;
1118 EditableList<string, EmailDialog>* _cc;
1121 wxButton* _reset_email;
1125 class CoverSheetPage : public Page
1129 CoverSheetPage (wxSize panel_size, int border)
1130 #ifdef DCPOMATIC_OSX
1131 /* We have to force both width and height of this one */
1132 : Page (wxSize (panel_size.GetWidth(), 128), border)
1134 : Page (panel_size, border)
1138 wxString GetName () const
1140 return _("Cover Sheet");
1143 #ifdef DCPOMATIC_OSX
1144 wxBitmap GetLargeIcon () const
1146 return wxBitmap(bitmap_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1153 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1154 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1156 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1157 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1159 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1160 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1163 void config_changed ()
1165 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1168 void cover_sheet_changed ()
1170 if (_cover_sheet->GetValue().IsEmpty ()) {
1171 /* Sometimes we get sent an erroneous notification that the cover sheet
1172 is empty; I don't know why.
1176 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1179 void reset_cover_sheet ()
1181 Config::instance()->reset_cover_sheet();
1182 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1185 wxTextCtrl* _cover_sheet;
1186 wxButton* _reset_cover_sheet;
1190 class IdentifiersPage : public Page
1193 IdentifiersPage (wxSize panel_size, int border)
1194 : Page (panel_size, border)
1197 wxString GetName () const
1199 return _("Identifiers");
1202 #ifdef DCPOMATIC_OSX
1203 wxBitmap GetLargeIcon () const
1205 return wxBitmap(bitmap_path("identifiers"), wxBITMAP_TYPE_PNG);
1212 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1213 table->AddGrowableCol (1, 1);
1215 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1216 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1217 _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."));
1218 table->Add (_issuer, 1, wxALL | wxEXPAND);
1220 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1221 _creator = new wxTextCtrl (_panel, wxID_ANY);
1222 _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."));
1223 table->Add (_creator, 1, wxALL | wxEXPAND);
1225 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1226 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1227 _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."));
1228 table->Add (_company_name, 1, wxALL | wxEXPAND);
1230 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1231 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1232 _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."));
1233 table->Add (_product_name, 1, wxALL | wxEXPAND);
1235 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1236 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1237 _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."));
1238 table->Add (_product_version, 1, wxALL | wxEXPAND);
1240 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1241 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1242 _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."));
1243 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1245 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1247 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1248 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1249 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1250 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1251 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1252 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1255 void config_changed ()
1257 auto config = Config::instance ();
1258 checked_set (_issuer, config->dcp_issuer ());
1259 checked_set (_creator, config->dcp_creator ());
1260 checked_set (_company_name, config->dcp_company_name ());
1261 checked_set (_product_name, config->dcp_product_name ());
1262 checked_set (_product_version, config->dcp_product_version ());
1263 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1266 void issuer_changed ()
1268 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1271 void creator_changed ()
1273 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1276 void company_name_changed ()
1278 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1281 void product_name_changed ()
1283 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1286 void product_version_changed ()
1288 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1291 void j2k_comment_changed ()
1293 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1296 wxTextCtrl* _issuer;
1297 wxTextCtrl* _creator;
1298 wxTextCtrl* _company_name;
1299 wxTextCtrl* _product_name;
1300 wxTextCtrl* _product_version;
1301 wxTextCtrl* _j2k_comment;
1305 /** @class AdvancedPage
1306 * @brief Advanced page of the preferences dialog.
1308 class AdvancedPage : public Page
1311 AdvancedPage (wxSize panel_size, int border)
1312 : Page (panel_size, border)
1315 wxString GetName () const
1317 return _("Advanced");
1320 #ifdef DCPOMATIC_OSX
1321 wxBitmap GetLargeIcon () const
1323 return wxBitmap(bitmap_path("advanced"), wxBITMAP_TYPE_PNG);
1328 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1330 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1332 flags |= wxALIGN_RIGHT;
1335 wxStaticText* m = new StaticText (parent, text);
1336 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1341 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1342 table->AddGrowableCol (1, 1);
1343 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1346 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1347 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1348 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1349 s->Add (_maximum_j2k_bandwidth, 1);
1350 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1354 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1355 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1356 table->Add (_video_display_mode);
1358 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1359 auto font = restart->GetFont();
1360 font.SetStyle (wxFONTSTYLE_ITALIC);
1361 font.SetPointSize (font.GetPointSize() - 1);
1362 restart->SetFont (font);
1363 table->AddSpacer (0);
1365 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1366 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1367 table->AddSpacer (0);
1369 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1370 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1371 table->AddSpacer (0);
1373 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1374 restart->SetFont (font);
1375 table->AddSpacer (0);
1377 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1378 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1379 table->AddSpacer (0);
1381 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1382 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1383 table->AddSpacer (0);
1386 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1387 auto s = new wxBoxSizer (wxHORIZONTAL);
1388 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1389 s->Add (_frames_in_memory_multiplier, 1);
1394 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1395 #ifdef DCPOMATIC_OSX
1396 auto align = new wxBoxSizer (wxHORIZONTAL);
1397 align->Add (format, 0, wxTOP, 2);
1398 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1400 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1402 dcp::NameFormat::Map titles;
1403 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1404 dcp::NameFormat::Map examples;
1405 examples['t'] = "cpl";
1406 _dcp_metadata_filename_format = new NameFormatEditor (
1407 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1409 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1413 auto format = create_label (_panel, _("DCP asset filename format"), true);
1414 #ifdef DCPOMATIC_OSX
1415 auto align = new wxBoxSizer (wxHORIZONTAL);
1416 align->Add (format, 0, wxTOP, 2);
1417 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1419 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1421 dcp::NameFormat::Map titles;
1422 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1423 titles['r'] = wx_to_std (_("reel number"));
1424 titles['n'] = wx_to_std (_("number of reels"));
1425 titles['c'] = wx_to_std (_("content filename"));
1426 dcp::NameFormat::Map examples;
1427 examples['t'] = "j2c";
1428 examples['r'] = "1";
1429 examples['n'] = "4";
1430 examples['c'] = "myfile.mp4";
1431 _dcp_asset_filename_format = new NameFormatEditor (
1432 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1434 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1438 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1439 auto t = new wxFlexGridSizer (2);
1440 _log_general = new CheckBox (_panel, _("General"));
1441 t->Add (_log_general, 1, wxEXPAND | wxALL);
1442 _log_warning = new CheckBox (_panel, _("Warnings"));
1443 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1444 _log_error = new CheckBox (_panel, _("Errors"));
1445 t->Add (_log_error, 1, wxEXPAND | wxALL);
1446 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1447 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1448 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1449 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1450 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1451 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1452 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1453 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1454 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1455 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1456 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1457 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1458 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1459 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1460 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1461 table->Add (t, 0, wxALL, 6);
1464 #ifdef DCPOMATIC_WINDOWS
1465 _win32_console = new CheckBox (_panel, _("Open console window"));
1466 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1467 table->AddSpacer (0);
1470 _maximum_j2k_bandwidth->SetRange (1, 1000);
1471 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1472 _video_display_mode->Append (_("Simple (safer)"));
1473 #if wxCHECK_VERSION(3, 1, 0)
1474 _video_display_mode->Append (_("OpenGL (faster)"));
1476 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1477 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1478 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1479 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1480 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1481 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1482 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1483 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1484 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1485 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1486 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1487 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1488 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1489 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1490 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1491 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1492 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1493 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1494 #ifdef DCPOMATIC_WINDOWS
1495 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1499 void config_changed ()
1501 auto config = Config::instance ();
1503 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1504 switch (config->video_view_type()) {
1505 case Config::VIDEO_VIEW_SIMPLE:
1506 checked_set (_video_display_mode, 0);
1508 case Config::VIDEO_VIEW_OPENGL:
1509 checked_set (_video_display_mode, 1);
1512 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1513 checked_set (_allow_any_container, config->allow_any_container ());
1514 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1515 checked_set (_only_servers_encode, config->only_servers_encode ());
1516 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1517 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1518 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1519 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1520 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1521 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1522 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1523 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1524 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1525 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1526 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1527 #ifdef DCPOMATIC_WINDOWS
1528 checked_set (_win32_console, config->win32_console());
1532 void maximum_j2k_bandwidth_changed ()
1534 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1537 void video_display_mode_changed ()
1539 if (_video_display_mode->GetSelection() == 0) {
1540 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1542 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1546 void frames_in_memory_multiplier_changed ()
1548 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1551 void allow_any_dcp_frame_rate_changed ()
1553 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1556 void allow_any_container_changed ()
1558 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1561 void show_experimental_audio_processors_changed ()
1563 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1566 void only_servers_encode_changed ()
1568 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1571 void dcp_metadata_filename_format_changed ()
1573 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1576 void dcp_asset_filename_format_changed ()
1578 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1584 if (_log_general->GetValue ()) {
1585 types |= LogEntry::TYPE_GENERAL;
1587 if (_log_warning->GetValue ()) {
1588 types |= LogEntry::TYPE_WARNING;
1590 if (_log_error->GetValue ()) {
1591 types |= LogEntry::TYPE_ERROR;
1593 if (_log_timing->GetValue ()) {
1594 types |= LogEntry::TYPE_TIMING;
1596 if (_log_debug_threed->GetValue ()) {
1597 types |= LogEntry::TYPE_DEBUG_THREE_D;
1599 if (_log_debug_encode->GetValue ()) {
1600 types |= LogEntry::TYPE_DEBUG_ENCODE;
1602 if (_log_debug_email->GetValue ()) {
1603 types |= LogEntry::TYPE_DEBUG_EMAIL;
1605 if (_log_debug_video_view->GetValue()) {
1606 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1608 if (_log_debug_player->GetValue()) {
1609 types |= LogEntry::TYPE_DEBUG_PLAYER;
1611 if (_log_debug_audio_analysis->GetValue()) {
1612 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1614 Config::instance()->set_log_types (types);
1617 #ifdef DCPOMATIC_WINDOWS
1618 void win32_console_changed ()
1620 Config::instance()->set_win32_console(_win32_console->GetValue());
1624 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1625 wxChoice* _video_display_mode = nullptr;
1626 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1627 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1628 wxCheckBox* _allow_any_container = nullptr;
1629 wxCheckBox* _show_experimental_audio_processors = nullptr;
1630 wxCheckBox* _only_servers_encode = nullptr;
1631 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1632 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1633 wxCheckBox* _log_general = nullptr;
1634 wxCheckBox* _log_warning = nullptr;
1635 wxCheckBox* _log_error = nullptr;
1636 wxCheckBox* _log_timing = nullptr;
1637 wxCheckBox* _log_debug_threed = nullptr;
1638 wxCheckBox* _log_debug_encode = nullptr;
1639 wxCheckBox* _log_debug_email = nullptr;
1640 wxCheckBox* _log_debug_video_view = nullptr;
1641 wxCheckBox* _log_debug_player = nullptr;
1642 wxCheckBox* _log_debug_audio_analysis = nullptr;
1643 #ifdef DCPOMATIC_WINDOWS
1644 wxCheckBox* _win32_console = nullptr;
1649 wxPreferencesEditor*
1650 create_full_config_dialog ()
1652 auto e = new wxPreferencesEditor ();
1654 #ifdef DCPOMATIC_OSX
1655 /* Width that we force some of the config panels to be on OSX so that
1656 the containing window doesn't shrink too much when we select those panels.
1657 This is obviously an unpleasant hack.
1659 wxSize ps = wxSize (750, -1);
1660 int const border = 16;
1662 wxSize ps = wxSize (-1, -1);
1663 int const border = 8;
1666 e->AddPage (new FullGeneralPage (ps, border));
1667 e->AddPage (new SoundPage (ps, border));
1668 e->AddPage (new DefaultsPage (ps, border));
1669 e->AddPage (new EncodingServersPage(ps, border));
1670 e->AddPage (new KeysPage (ps, border));
1671 e->AddPage (new TMSPage (ps, border));
1672 e->AddPage (new EmailPage (ps, border));
1673 e->AddPage (new KDMEmailPage (ps, border));
1674 e->AddPage (new NotificationsPage (ps, border));
1675 e->AddPage (new CoverSheetPage (ps, border));
1676 e->AddPage (new IdentifiersPage (ps, border));
1677 e->AddPage (new AdvancedPage (ps, border));