2 Copyright (C) 2012-2021 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
22 /** @file src/full_config_dialog.cc
23 * @brief A dialogue to edit all DCP-o-matic configuration.
27 #include "check_box.h"
28 #include "config_dialog.h"
29 #include "config_move_dialog.h"
30 #include "dcpomatic_button.h"
31 #include "dir_picker_ctrl.h"
32 #include "editable_list.h"
33 #include "email_dialog.h"
34 #include "file_picker_ctrl.h"
35 #include "filter_dialog.h"
36 #include "full_config_dialog.h"
37 #include "kdm_choice.h"
38 #include "make_chain_dialog.h"
39 #include "nag_dialog.h"
40 #include "name_format_editor.h"
41 #include "password_entry.h"
42 #include "server_dialog.h"
43 #include "static_text.h"
45 #include "lib/config.h"
46 #include "lib/cross.h"
47 #include "lib/dcp_content_type.h"
48 #include "lib/exceptions.h"
49 #include "lib/filter.h"
51 #include "lib/ratio.h"
53 #include <dcp/certificate_chain.h>
54 #include <dcp/exceptions.h>
55 #include <dcp/locale_convert.h>
56 #include <wx/filepicker.h>
57 #include <wx/preferences.h>
58 #include <wx/spinctrl.h>
59 #include <wx/stdpaths.h>
61 #include <boost/filesystem.hpp>
71 using std::shared_ptr;
75 using boost::optional;
76 #if BOOST_VERSION >= 106100
77 using namespace boost::placeholders;
79 using dcp::locale_convert;
82 class FullGeneralPage : public GeneralPage
85 FullGeneralPage (wxSize panel_size, int border)
86 : GeneralPage (panel_size, border)
92 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
93 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
96 add_language_controls (table, r);
98 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
99 _master_encoding_threads = new wxSpinCtrl (_panel);
100 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
103 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
104 _server_encoding_threads = new wxSpinCtrl (_panel);
105 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
108 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
109 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
110 table->Add (_config_file, wxGBPosition (r, 1));
113 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
114 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
115 table->Add (_cinemas_file, wxGBPosition (r, 1));
116 Button* export_cinemas = new Button (_panel, _("Export..."));
117 table->Add (export_cinemas, wxGBPosition (r, 2));
120 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
121 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
122 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
126 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
127 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
130 add_update_controls (table, r);
132 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
133 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
135 _master_encoding_threads->SetRange (1, 128);
136 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
137 _server_encoding_threads->SetRange (1, 128);
138 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
139 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
141 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
142 _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
144 _automatic_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::automatic_audio_analysis_changed, this));
147 void config_changed ()
149 auto config = Config::instance ();
151 checked_set (_master_encoding_threads, config->master_encoding_threads ());
152 checked_set (_server_encoding_threads, config->server_encoding_threads ());
153 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
154 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
156 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
157 checked_set (_config_file, config->config_read_file());
158 checked_set (_cinemas_file, config->cinemas_file());
160 GeneralPage::config_changed ();
163 void export_cinemas_file ()
165 auto d = new wxFileDialog (
166 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
167 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
170 if (d->ShowModal () == wxID_OK) {
171 boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
176 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
177 void analyse_ebur128_changed ()
179 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
183 void automatic_audio_analysis_changed ()
185 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
188 void master_encoding_threads_changed ()
190 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
193 void server_encoding_threads_changed ()
195 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
198 void config_file_changed ()
200 auto config = Config::instance();
201 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
202 if (new_file == config->config_read_file()) {
205 bool copy_and_link = true;
206 if (boost::filesystem::exists(new_file)) {
207 auto d = new ConfigMoveDialog (_panel, new_file);
208 if (d->ShowModal() == wxID_OK) {
209 copy_and_link = false;
216 if (new_file != config->config_read_file()) {
217 config->copy_and_link (new_file);
220 config->link (new_file);
224 void cinemas_file_changed ()
226 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
229 wxSpinCtrl* _master_encoding_threads;
230 wxSpinCtrl* _server_encoding_threads;
231 FilePickerCtrl* _config_file;
232 FilePickerCtrl* _cinemas_file;
233 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
234 wxCheckBox* _analyse_ebur128;
236 wxCheckBox* _automatic_audio_analysis;
240 class DefaultsPage : public Page
243 DefaultsPage (wxSize panel_size, int border)
244 : Page (panel_size, border)
247 wxString GetName () const
249 return _("Defaults");
253 wxBitmap GetLargeIcon () const
255 return wxBitmap(bitmap_path("defaults"), wxBITMAP_TYPE_PNG);
262 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
263 table->AddGrowableCol (1, 1);
264 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
267 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
268 auto s = new wxBoxSizer (wxHORIZONTAL);
269 _still_length = new wxSpinCtrl (_panel);
270 s->Add (_still_length);
271 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
275 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
276 #ifdef DCPOMATIC_USE_OWN_PICKER
277 _directory = new DirPickerCtrl (_panel);
279 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
281 table->Add (_directory, 1, wxEXPAND);
283 add_label_to_sizer (table, _panel, _("Default container"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
284 _container = new wxChoice (_panel, wxID_ANY);
285 table->Add (_container);
287 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
288 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
289 table->Add (_dcp_content_type);
291 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
292 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
293 table->Add (_dcp_audio_channels);
296 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
297 auto s = new wxBoxSizer (wxHORIZONTAL);
298 _j2k_bandwidth = new wxSpinCtrl (_panel);
299 s->Add (_j2k_bandwidth);
300 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
305 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
306 auto s = new wxBoxSizer (wxHORIZONTAL);
307 _audio_delay = new wxSpinCtrl (_panel);
308 s->Add (_audio_delay);
309 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
313 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
314 _standard = new wxChoice (_panel, wxID_ANY);
315 table->Add (_standard);
317 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
318 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
320 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
321 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
323 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
324 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
326 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
327 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
329 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
330 #ifdef DCPOMATIC_USE_OWN_PICKER
331 _kdm_directory = new DirPickerCtrl (_panel);
333 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
335 table->Add (_kdm_directory, 1, wxEXPAND);
337 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
338 _kdm_type = new KDMChoice (_panel);
339 table->Add (_kdm_type, 1, wxEXPAND);
341 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
343 _still_length->SetRange (1, 3600);
344 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
346 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
347 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
348 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
350 _use_isdcf_name_by_default->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::use_isdcf_name_by_default_changed, this));
352 for (auto i: Ratio::containers()) {
353 _container->Append (std_to_wx(i->container_nickname()));
356 _container->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::container_changed, this));
358 for (auto i: DCPContentType::all()) {
359 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
362 setup_audio_channels_choice (_dcp_audio_channels, 2);
364 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
365 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
367 _j2k_bandwidth->SetRange (50, 250);
368 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
370 _audio_delay->SetRange (-1000, 1000);
371 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
373 _standard->Append (_("SMPTE"));
374 _standard->Append (_("Interop"));
375 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
377 for (auto const& i: _enable_metadata) {
378 i.second->Bind (wxEVT_CHECKBOX, boost::bind(&DefaultsPage::metadata_changed, this));
381 for (auto const& i: _metadata) {
382 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
386 void config_changed ()
388 auto config = Config::instance ();
390 auto containers = Ratio::containers ();
391 for (size_t i = 0; i < containers.size(); ++i) {
392 if (containers[i] == config->default_container()) {
393 _container->SetSelection (i);
397 auto const ct = DCPContentType::all ();
398 for (size_t i = 0; i < ct.size(); ++i) {
399 if (ct[i] == config->default_dcp_content_type()) {
400 _dcp_content_type->SetSelection (i);
404 checked_set (_still_length, config->default_still_length ());
405 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
406 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
407 _kdm_type->set (config->default_kdm_type());
408 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
409 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
410 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
411 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
412 checked_set (_audio_delay, config->default_audio_delay ());
413 checked_set (_standard, config->default_interop() ? 1 : 0);
415 auto metadata = config->default_metadata();
417 for (auto const& i: metadata) {
418 _enable_metadata[i.first]->SetValue(true);
419 checked_set (_metadata[i.first], i.second);
422 for (auto const& i: _enable_metadata) {
423 if (metadata.find(i.first) == metadata.end()) {
424 checked_set (i.second, false);
428 for (auto const& i: _metadata) {
429 if (metadata.find(i.first) == metadata.end()) {
430 checked_set (i.second, wxT(""));
434 setup_sensitivity ();
437 void j2k_bandwidth_changed ()
439 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
442 void audio_delay_changed ()
444 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
447 void dcp_audio_channels_changed ()
449 int const s = _dcp_audio_channels->GetSelection ();
450 if (s != wxNOT_FOUND) {
451 Config::instance()->set_default_dcp_audio_channels (
452 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
457 void directory_changed ()
459 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
462 void kdm_directory_changed ()
464 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
467 void kdm_type_changed ()
469 Config::instance()->set_default_kdm_type(_kdm_type->get());
472 void use_isdcf_name_by_default_changed ()
474 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
477 void still_length_changed ()
479 Config::instance()->set_default_still_length (_still_length->GetValue ());
482 void container_changed ()
484 auto ratio = Ratio::containers ();
485 Config::instance()->set_default_container (ratio[_container->GetSelection()]);
488 void dcp_content_type_changed ()
490 auto ct = DCPContentType::all ();
491 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
494 void standard_changed ()
496 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
499 void metadata_changed ()
501 map<string, string> metadata;
502 for (auto const& i: _enable_metadata) {
503 if (i.second->GetValue()) {
504 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
507 Config::instance()->set_default_metadata (metadata);
508 setup_sensitivity ();
511 void setup_sensitivity ()
513 for (auto const& i: _enable_metadata) {
514 _metadata[i.first]->Enable(i.second->GetValue());
518 wxSpinCtrl* _j2k_bandwidth;
519 wxSpinCtrl* _audio_delay;
520 wxSpinCtrl* _still_length;
521 #ifdef DCPOMATIC_USE_OWN_PICKER
522 DirPickerCtrl* _directory;
523 DirPickerCtrl* _kdm_directory;
525 wxDirPickerCtrl* _directory;
526 wxDirPickerCtrl* _kdm_directory;
528 KDMChoice* _kdm_type;
529 wxCheckBox* _use_isdcf_name_by_default;
530 wxChoice* _container;
531 wxChoice* _dcp_content_type;
532 wxChoice* _dcp_audio_channels;
534 map<string, CheckBox*> _enable_metadata;
535 map<string, wxTextCtrl*> _metadata;
539 class EncodingServersPage : public Page
542 EncodingServersPage (wxSize panel_size, int border)
543 : Page (panel_size, border)
546 wxString GetName () const
552 wxBitmap GetLargeIcon () const
554 return wxBitmap(bitmap_path("servers"), wxBITMAP_TYPE_PNG);
561 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
562 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
564 vector<EditableListColumn> columns;
565 columns.push_back (EditableListColumn(_("IP address / host name")));
566 _servers_list = new EditableList<string, ServerDialog> (
569 boost::bind (&Config::servers, Config::instance()),
570 boost::bind (&Config::set_servers, Config::instance(), _1),
571 boost::bind (&EncodingServersPage::server_column, this, _1)
574 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
576 _use_any_servers->Bind (wxEVT_CHECKBOX, boost::bind(&EncodingServersPage::use_any_servers_changed, this));
579 void config_changed ()
581 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
582 _servers_list->refresh ();
585 void use_any_servers_changed ()
587 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
590 string server_column (string s)
595 wxCheckBox* _use_any_servers;
596 EditableList<string, ServerDialog>* _servers_list;
600 class TMSPage : public Page
603 TMSPage (wxSize panel_size, int border)
604 : Page (panel_size, border)
607 wxString GetName () const
613 wxBitmap GetLargeIcon () const
615 return wxBitmap(bitmap_path("tms"), wxBITMAP_TYPE_PNG);
622 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
623 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
625 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
626 table->AddGrowableCol (1, 1);
627 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
629 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
630 _tms_protocol = new wxChoice (_panel, wxID_ANY);
631 table->Add (_tms_protocol, 1, wxEXPAND);
633 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
634 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
635 table->Add (_tms_ip, 1, wxEXPAND);
637 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
638 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
639 table->Add (_tms_path, 1, wxEXPAND);
641 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
642 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
643 table->Add (_tms_user, 1, wxEXPAND);
645 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
646 _tms_password = new PasswordEntry (_panel);
647 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
649 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
650 _tms_protocol->Append (_("FTP (for Dolby)"));
652 _upload->Bind (wxEVT_CHECKBOX, boost::bind(&TMSPage::upload_changed, this));
653 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
654 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
655 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
656 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
657 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
660 void config_changed ()
662 auto config = Config::instance ();
664 checked_set (_upload, config->upload_after_make_dcp());
665 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
666 checked_set (_tms_ip, config->tms_ip ());
667 checked_set (_tms_path, config->tms_path ());
668 checked_set (_tms_user, config->tms_user ());
669 checked_set (_tms_password, config->tms_password ());
672 void upload_changed ()
674 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
677 void tms_protocol_changed ()
679 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
682 void tms_ip_changed ()
684 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
687 void tms_path_changed ()
689 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
692 void tms_user_changed ()
694 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
697 void tms_password_changed ()
699 Config::instance()->set_tms_password (_tms_password->get());
703 wxChoice* _tms_protocol;
705 wxTextCtrl* _tms_path;
706 wxTextCtrl* _tms_user;
707 PasswordEntry* _tms_password;
711 class EmailPage : public Page
714 EmailPage (wxSize panel_size, int border)
715 : Page (panel_size, border)
718 wxString GetName () const
724 wxBitmap GetLargeIcon () const
726 return wxBitmap(bitmap_path("email"), wxBITMAP_TYPE_PNG);
733 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
734 table->AddGrowableCol (1, 1);
735 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
737 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
739 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
740 _server = new wxTextCtrl (_panel, wxID_ANY);
741 s->Add (_server, 1, wxEXPAND | wxALL);
742 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
743 _port = new wxSpinCtrl (_panel, wxID_ANY);
744 _port->SetRange (0, 65535);
746 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
747 _protocol = new wxChoice (_panel, wxID_ANY);
748 /* Make sure this matches the switches in config_changed and port_changed below */
749 _protocol->Append (_("Auto"));
750 _protocol->Append (_("Plain"));
751 _protocol->Append (_("STARTTLS"));
752 _protocol->Append (_("SSL"));
753 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
754 table->Add (s, 1, wxEXPAND | wxALL);
757 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
758 _user = new wxTextCtrl (_panel, wxID_ANY);
759 table->Add (_user, 1, wxEXPAND | wxALL);
761 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
762 _password = new PasswordEntry (_panel);
763 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
765 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
766 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
767 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
768 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
769 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
772 void config_changed ()
774 auto config = Config::instance ();
776 checked_set (_server, config->mail_server());
777 checked_set (_port, config->mail_port());
778 switch (config->mail_protocol()) {
779 case EmailProtocol::AUTO:
780 checked_set (_protocol, 0);
782 case EmailProtocol::PLAIN:
783 checked_set (_protocol, 1);
785 case EmailProtocol::STARTTLS:
786 checked_set (_protocol, 2);
788 case EmailProtocol::SSL:
789 checked_set (_protocol, 3);
792 checked_set (_user, config->mail_user());
793 checked_set (_password, config->mail_password());
796 void server_changed ()
798 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
803 Config::instance()->set_mail_port(_port->GetValue());
806 void protocol_changed ()
808 switch (_protocol->GetSelection()) {
810 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
813 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
816 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
819 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
826 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
829 void password_changed ()
831 Config::instance()->set_mail_password(_password->get());
838 PasswordEntry* _password;
842 class KDMEmailPage : public Page
846 KDMEmailPage (wxSize panel_size, int border)
848 /* We have to force both width and height of this one */
849 : Page (wxSize (panel_size.GetWidth(), 128), border)
851 : Page (panel_size, border)
855 wxString GetName () const
857 return _("KDM Email");
861 wxBitmap GetLargeIcon () const
863 return wxBitmap(bitmap_path("kdm_email"), wxBITMAP_TYPE_PNG);
870 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
871 table->AddGrowableCol (1, 1);
872 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
874 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
875 _subject = new wxTextCtrl (_panel, wxID_ANY);
876 table->Add (_subject, 1, wxEXPAND | wxALL);
878 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
879 _from = new wxTextCtrl (_panel, wxID_ANY);
880 table->Add (_from, 1, wxEXPAND | wxALL);
882 vector<EditableListColumn> columns;
883 columns.push_back (EditableListColumn(_("Address")));
884 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
885 _cc = new EditableList<string, EmailDialog> (
888 bind (&Config::kdm_cc, Config::instance()),
889 bind (&Config::set_kdm_cc, Config::instance(), _1),
893 table->Add (_cc, 1, wxEXPAND | wxALL);
895 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
896 _bcc = new wxTextCtrl (_panel, wxID_ANY);
897 table->Add (_bcc, 1, wxEXPAND | wxALL);
899 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
900 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
902 _reset_email = new Button (_panel, _("Reset to default subject and text"));
903 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
907 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
908 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
909 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
910 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
911 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
914 void config_changed ()
916 Config* config = Config::instance ();
918 checked_set (_subject, config->kdm_subject ());
919 checked_set (_from, config->kdm_from ());
920 checked_set (_bcc, config->kdm_bcc ());
921 checked_set (_email, Config::instance()->kdm_email ());
924 void kdm_subject_changed ()
926 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
929 void kdm_from_changed ()
931 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
934 void kdm_bcc_changed ()
936 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
939 void kdm_email_changed ()
941 if (_email->GetValue().IsEmpty ()) {
942 /* Sometimes we get sent an erroneous notification that the email
943 is empty; I don't know why.
947 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
952 Config::instance()->reset_kdm_email ();
953 checked_set (_email, Config::instance()->kdm_email ());
956 wxTextCtrl* _subject;
958 EditableList<string, EmailDialog>* _cc;
961 wxButton* _reset_email;
965 class NotificationsPage : public Page
968 NotificationsPage (wxSize panel_size, int border)
970 /* We have to force both width and height of this one */
971 : Page (wxSize (panel_size.GetWidth(), 128), border)
973 : Page (panel_size, border)
977 wxString GetName () const
979 return _("Notifications");
983 wxBitmap GetLargeIcon () const
985 return wxBitmap(bitmap_path("notifications"), wxBITMAP_TYPE_PNG);
992 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
993 table->AddGrowableCol (1, 1);
994 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
996 _enable_message_box = new CheckBox (_panel, _("Message box"));
997 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
998 table->AddSpacer (0);
1000 _enable_email = new CheckBox (_panel, _("Email"));
1001 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1002 table->AddSpacer (0);
1004 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1005 _subject = new wxTextCtrl (_panel, wxID_ANY);
1006 table->Add (_subject, 1, wxEXPAND | wxALL);
1008 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1009 _from = new wxTextCtrl (_panel, wxID_ANY);
1010 table->Add (_from, 1, wxEXPAND | wxALL);
1012 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1013 _to = new wxTextCtrl (_panel, wxID_ANY);
1014 table->Add (_to, 1, wxEXPAND | wxALL);
1016 vector<EditableListColumn> columns;
1017 columns.push_back (EditableListColumn(_("Address")));
1018 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1019 _cc = new EditableList<string, EmailDialog> (
1022 bind (&Config::notification_cc, Config::instance()),
1023 bind (&Config::set_notification_cc, Config::instance(), _1),
1024 [] (string s, int) {
1027 table->Add (_cc, 1, wxEXPAND | wxALL);
1029 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1030 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1031 table->Add (_bcc, 1, wxEXPAND | wxALL);
1033 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1034 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1036 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1037 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1041 _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
1042 _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
1044 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1045 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1046 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1047 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1048 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1049 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1051 setup_sensitivity ();
1054 void setup_sensitivity ()
1056 bool const s = _enable_email->GetValue();
1057 _subject->Enable(s);
1063 _reset_email->Enable(s);
1066 void config_changed ()
1068 auto config = Config::instance ();
1070 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1071 checked_set (_enable_email, config->notification(Config::EMAIL));
1072 checked_set (_subject, config->notification_subject ());
1073 checked_set (_from, config->notification_from ());
1074 checked_set (_to, config->notification_to ());
1075 checked_set (_bcc, config->notification_bcc ());
1076 checked_set (_email, Config::instance()->notification_email ());
1078 setup_sensitivity ();
1081 void notification_subject_changed ()
1083 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1086 void notification_from_changed ()
1088 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1091 void notification_to_changed ()
1093 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1096 void notification_bcc_changed ()
1098 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1101 void notification_email_changed ()
1103 if (_email->GetValue().IsEmpty()) {
1104 /* Sometimes we get sent an erroneous notification that the email
1105 is empty; I don't know why.
1109 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1114 Config::instance()->reset_notification_email();
1115 checked_set (_email, Config::instance()->notification_email());
1118 void type_changed (wxCheckBox* b, Config::Notification n)
1120 Config::instance()->set_notification(n, b->GetValue());
1121 setup_sensitivity ();
1124 wxCheckBox* _enable_message_box;
1125 wxCheckBox* _enable_email;
1127 wxTextCtrl* _subject;
1130 EditableList<string, EmailDialog>* _cc;
1133 wxButton* _reset_email;
1137 class CoverSheetPage : public Page
1141 CoverSheetPage (wxSize panel_size, int border)
1142 #ifdef DCPOMATIC_OSX
1143 /* We have to force both width and height of this one */
1144 : Page (wxSize (panel_size.GetWidth(), 128), border)
1146 : Page (panel_size, border)
1150 wxString GetName () const
1152 return _("Cover Sheet");
1155 #ifdef DCPOMATIC_OSX
1156 wxBitmap GetLargeIcon () const
1158 return wxBitmap(bitmap_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1165 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1166 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1168 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1169 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1171 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1172 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1175 void config_changed ()
1177 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1180 void cover_sheet_changed ()
1182 if (_cover_sheet->GetValue().IsEmpty ()) {
1183 /* Sometimes we get sent an erroneous notification that the cover sheet
1184 is empty; I don't know why.
1188 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1191 void reset_cover_sheet ()
1193 Config::instance()->reset_cover_sheet();
1194 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1197 wxTextCtrl* _cover_sheet;
1198 wxButton* _reset_cover_sheet;
1202 class IdentifiersPage : public Page
1205 IdentifiersPage (wxSize panel_size, int border)
1206 : Page (panel_size, border)
1209 wxString GetName () const
1211 return _("Identifiers");
1214 #ifdef DCPOMATIC_OSX
1215 wxBitmap GetLargeIcon () const
1217 return wxBitmap(bitmap_path("identifiers"), wxBITMAP_TYPE_PNG);
1224 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1225 table->AddGrowableCol (1, 1);
1227 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1228 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1229 _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."));
1230 table->Add (_issuer, 1, wxALL | wxEXPAND);
1232 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1233 _creator = new wxTextCtrl (_panel, wxID_ANY);
1234 _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."));
1235 table->Add (_creator, 1, wxALL | wxEXPAND);
1237 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1238 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1239 _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."));
1240 table->Add (_company_name, 1, wxALL | wxEXPAND);
1242 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1243 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1244 _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."));
1245 table->Add (_product_name, 1, wxALL | wxEXPAND);
1247 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1248 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1249 _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."));
1250 table->Add (_product_version, 1, wxALL | wxEXPAND);
1252 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1253 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1254 _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."));
1255 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1257 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1259 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1260 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1261 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1262 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1263 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1264 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1267 void config_changed ()
1269 auto config = Config::instance ();
1270 checked_set (_issuer, config->dcp_issuer ());
1271 checked_set (_creator, config->dcp_creator ());
1272 checked_set (_company_name, config->dcp_company_name ());
1273 checked_set (_product_name, config->dcp_product_name ());
1274 checked_set (_product_version, config->dcp_product_version ());
1275 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1278 void issuer_changed ()
1280 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1283 void creator_changed ()
1285 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1288 void company_name_changed ()
1290 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1293 void product_name_changed ()
1295 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1298 void product_version_changed ()
1300 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1303 void j2k_comment_changed ()
1305 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1308 wxTextCtrl* _issuer;
1309 wxTextCtrl* _creator;
1310 wxTextCtrl* _company_name;
1311 wxTextCtrl* _product_name;
1312 wxTextCtrl* _product_version;
1313 wxTextCtrl* _j2k_comment;
1317 /** @class AdvancedPage
1318 * @brief Advanced page of the preferences dialog.
1320 class AdvancedPage : public Page
1323 AdvancedPage (wxSize panel_size, int border)
1324 : Page (panel_size, border)
1327 wxString GetName () const
1329 return _("Advanced");
1332 #ifdef DCPOMATIC_OSX
1333 wxBitmap GetLargeIcon () const
1335 return wxBitmap(bitmap_path("advanced"), wxBITMAP_TYPE_PNG);
1340 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1342 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1344 flags |= wxALIGN_RIGHT;
1347 wxStaticText* m = new StaticText (parent, text);
1348 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1353 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1354 table->AddGrowableCol (1, 1);
1355 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1358 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1359 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1360 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1361 s->Add (_maximum_j2k_bandwidth, 1);
1362 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1366 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1367 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1368 table->Add (_video_display_mode);
1370 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1371 auto font = restart->GetFont();
1372 font.SetStyle (wxFONTSTYLE_ITALIC);
1373 font.SetPointSize (font.GetPointSize() - 1);
1374 restart->SetFont (font);
1375 table->AddSpacer (0);
1377 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1378 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
1379 table->AddSpacer (0);
1381 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1382 table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
1383 table->AddSpacer (0);
1385 restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
1386 restart->SetFont (font);
1387 table->AddSpacer (0);
1389 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1390 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL);
1391 table->AddSpacer (0);
1393 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1394 table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
1395 table->AddSpacer (0);
1398 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1399 auto s = new wxBoxSizer (wxHORIZONTAL);
1400 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1401 s->Add (_frames_in_memory_multiplier, 1);
1406 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1407 #ifdef DCPOMATIC_OSX
1408 auto align = new wxBoxSizer (wxHORIZONTAL);
1409 align->Add (format, 0, wxTOP, 2);
1410 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1412 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1414 dcp::NameFormat::Map titles;
1415 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1416 dcp::NameFormat::Map examples;
1417 examples['t'] = "cpl";
1418 _dcp_metadata_filename_format = new NameFormatEditor (
1419 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1421 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1425 auto format = create_label (_panel, _("DCP asset filename format"), true);
1426 #ifdef DCPOMATIC_OSX
1427 auto align = new wxBoxSizer (wxHORIZONTAL);
1428 align->Add (format, 0, wxTOP, 2);
1429 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1431 table->Add (format, 0, wxTOP | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1433 dcp::NameFormat::Map titles;
1434 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1435 titles['r'] = wx_to_std (_("reel number"));
1436 titles['n'] = wx_to_std (_("number of reels"));
1437 titles['c'] = wx_to_std (_("content filename"));
1438 dcp::NameFormat::Map examples;
1439 examples['t'] = "j2c";
1440 examples['r'] = "1";
1441 examples['n'] = "4";
1442 examples['c'] = "myfile.mp4";
1443 _dcp_asset_filename_format = new NameFormatEditor (
1444 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1446 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1450 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1451 auto t = new wxFlexGridSizer (2);
1452 _log_general = new CheckBox (_panel, _("General"));
1453 t->Add (_log_general, 1, wxEXPAND | wxALL);
1454 _log_warning = new CheckBox (_panel, _("Warnings"));
1455 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1456 _log_error = new CheckBox (_panel, _("Errors"));
1457 t->Add (_log_error, 1, wxEXPAND | wxALL);
1458 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1459 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1460 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1461 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1462 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1463 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1464 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1465 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1466 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1467 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1468 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1469 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1470 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1471 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1472 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1473 table->Add (t, 0, wxALL, 6);
1476 #ifdef DCPOMATIC_WINDOWS
1477 _win32_console = new CheckBox (_panel, _("Open console window"));
1478 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1479 table->AddSpacer (0);
1482 _maximum_j2k_bandwidth->SetRange (1, 1000);
1483 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1484 _video_display_mode->Append (_("Simple (safer)"));
1485 #if wxCHECK_VERSION(3, 1, 0)
1486 _video_display_mode->Append (_("OpenGL (faster)"));
1488 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1489 _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
1490 _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
1491 _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this));
1492 _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
1493 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1494 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1495 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1496 _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1497 _log_warning->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1498 _log_error->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1499 _log_timing->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1500 _log_debug_threed->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1501 _log_debug_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1502 _log_debug_email->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1503 _log_debug_video_view->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1504 _log_debug_player->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1505 _log_debug_audio_analysis->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
1506 #ifdef DCPOMATIC_WINDOWS
1507 _win32_console->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::win32_console_changed, this));
1511 void config_changed ()
1513 auto config = Config::instance ();
1515 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1516 switch (config->video_view_type()) {
1517 case Config::VIDEO_VIEW_SIMPLE:
1518 checked_set (_video_display_mode, 0);
1520 case Config::VIDEO_VIEW_OPENGL:
1521 checked_set (_video_display_mode, 1);
1524 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1525 checked_set (_allow_any_container, config->allow_any_container ());
1526 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1527 checked_set (_only_servers_encode, config->only_servers_encode ());
1528 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1529 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1530 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1531 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1532 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1533 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1534 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1535 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1536 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1537 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1538 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1539 #ifdef DCPOMATIC_WINDOWS
1540 checked_set (_win32_console, config->win32_console());
1544 void maximum_j2k_bandwidth_changed ()
1546 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1549 void video_display_mode_changed ()
1551 if (_video_display_mode->GetSelection() == 0) {
1552 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1554 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1558 void frames_in_memory_multiplier_changed ()
1560 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1563 void allow_any_dcp_frame_rate_changed ()
1565 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1568 void allow_any_container_changed ()
1570 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1573 void show_experimental_audio_processors_changed ()
1575 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1578 void only_servers_encode_changed ()
1580 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1583 void dcp_metadata_filename_format_changed ()
1585 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1588 void dcp_asset_filename_format_changed ()
1590 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1596 if (_log_general->GetValue ()) {
1597 types |= LogEntry::TYPE_GENERAL;
1599 if (_log_warning->GetValue ()) {
1600 types |= LogEntry::TYPE_WARNING;
1602 if (_log_error->GetValue ()) {
1603 types |= LogEntry::TYPE_ERROR;
1605 if (_log_timing->GetValue ()) {
1606 types |= LogEntry::TYPE_TIMING;
1608 if (_log_debug_threed->GetValue ()) {
1609 types |= LogEntry::TYPE_DEBUG_THREE_D;
1611 if (_log_debug_encode->GetValue ()) {
1612 types |= LogEntry::TYPE_DEBUG_ENCODE;
1614 if (_log_debug_email->GetValue ()) {
1615 types |= LogEntry::TYPE_DEBUG_EMAIL;
1617 if (_log_debug_video_view->GetValue()) {
1618 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1620 if (_log_debug_player->GetValue()) {
1621 types |= LogEntry::TYPE_DEBUG_PLAYER;
1623 if (_log_debug_audio_analysis->GetValue()) {
1624 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1626 Config::instance()->set_log_types (types);
1629 #ifdef DCPOMATIC_WINDOWS
1630 void win32_console_changed ()
1632 Config::instance()->set_win32_console(_win32_console->GetValue());
1636 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1637 wxChoice* _video_display_mode = nullptr;
1638 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1639 wxCheckBox* _allow_any_dcp_frame_rate = nullptr;
1640 wxCheckBox* _allow_any_container = nullptr;
1641 wxCheckBox* _show_experimental_audio_processors = nullptr;
1642 wxCheckBox* _only_servers_encode = nullptr;
1643 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1644 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1645 wxCheckBox* _log_general = nullptr;
1646 wxCheckBox* _log_warning = nullptr;
1647 wxCheckBox* _log_error = nullptr;
1648 wxCheckBox* _log_timing = nullptr;
1649 wxCheckBox* _log_debug_threed = nullptr;
1650 wxCheckBox* _log_debug_encode = nullptr;
1651 wxCheckBox* _log_debug_email = nullptr;
1652 wxCheckBox* _log_debug_video_view = nullptr;
1653 wxCheckBox* _log_debug_player = nullptr;
1654 wxCheckBox* _log_debug_audio_analysis = nullptr;
1655 #ifdef DCPOMATIC_WINDOWS
1656 wxCheckBox* _win32_console = nullptr;
1661 wxPreferencesEditor*
1662 create_full_config_dialog ()
1664 auto e = new wxPreferencesEditor ();
1666 #ifdef DCPOMATIC_OSX
1667 /* Width that we force some of the config panels to be on OSX so that
1668 the containing window doesn't shrink too much when we select those panels.
1669 This is obviously an unpleasant hack.
1671 wxSize ps = wxSize (750, -1);
1672 int const border = 16;
1674 wxSize ps = wxSize (-1, -1);
1675 int const border = 8;
1678 e->AddPage (new FullGeneralPage (ps, border));
1679 e->AddPage (new SoundPage (ps, border));
1680 e->AddPage (new DefaultsPage (ps, border));
1681 e->AddPage (new EncodingServersPage(ps, border));
1682 e->AddPage (new KeysPage (ps, border));
1683 e->AddPage (new TMSPage (ps, border));
1684 e->AddPage (new EmailPage (ps, border));
1685 e->AddPage (new KDMEmailPage (ps, border));
1686 e->AddPage (new NotificationsPage (ps, border));
1687 e->AddPage (new CoverSheetPage (ps, border));
1688 e->AddPage (new IdentifiersPage (ps, border));
1689 e->AddPage (new AdvancedPage (ps, border));