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 "language_tag_widget.h"
39 #include "make_chain_dialog.h"
40 #include "nag_dialog.h"
41 #include "name_format_editor.h"
42 #include "password_entry.h"
43 #include "send_test_email_dialog.h"
44 #include "server_dialog.h"
45 #include "static_text.h"
47 #include "lib/config.h"
48 #include "lib/cross.h"
49 #include "lib/dcp_content_type.h"
50 #include "lib/emailer.h"
51 #include "lib/exceptions.h"
52 #include "lib/filter.h"
54 #include "lib/ratio.h"
56 #include <dcp/certificate_chain.h>
57 #include <dcp/exceptions.h>
58 #include <dcp/locale_convert.h>
59 #include <dcp/warnings.h>
60 LIBDCP_DISABLE_WARNINGS
61 #include <wx/filepicker.h>
62 #include <wx/preferences.h>
63 #include <wx/spinctrl.h>
64 #include <wx/stdpaths.h>
65 LIBDCP_ENABLE_WARNINGS
67 #include <boost/filesystem.hpp>
77 using std::shared_ptr;
81 using boost::optional;
82 #if BOOST_VERSION >= 106100
83 using namespace boost::placeholders;
85 using dcp::locale_convert;
88 class FullGeneralPage : public GeneralPage
91 FullGeneralPage (wxSize panel_size, int border)
92 : GeneralPage (panel_size, border)
96 void setup () override
98 auto table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
99 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
102 add_language_controls (table, r);
104 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
105 _master_encoding_threads = new wxSpinCtrl (_panel);
106 table->Add (_master_encoding_threads, wxGBPosition (r, 1));
109 add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic encode server should use"), true, wxGBPosition (r, 0));
110 _server_encoding_threads = new wxSpinCtrl (_panel);
111 table->Add (_server_encoding_threads, wxGBPosition (r, 1));
114 add_label_to_sizer (table, _panel, _("Configuration file"), true, wxGBPosition (r, 0));
115 _config_file = new FilePickerCtrl (_panel, _("Select configuration file"), "*.xml", true, false);
116 table->Add (_config_file, wxGBPosition (r, 1));
119 add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
120 _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true, false);
121 table->Add (_cinemas_file, wxGBPosition (r, 1));
122 auto export_cinemas = new Button (_panel, _("Export..."));
123 table->Add (export_cinemas, wxGBPosition (r, 2));
126 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
127 _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
128 table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
132 _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
133 table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
136 add_update_controls (table, r);
138 _config_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::config_file_changed, this));
139 _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind(&FullGeneralPage::cinemas_file_changed, this));
141 _master_encoding_threads->SetRange (1, 128);
142 _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
143 _server_encoding_threads->SetRange (1, 128);
144 _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
145 export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
147 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
148 _analyse_ebur128->bind(&FullGeneralPage::analyse_ebur128_changed, this);
150 _automatic_audio_analysis->bind(&FullGeneralPage::automatic_audio_analysis_changed, this);
153 void config_changed () override
155 auto config = Config::instance ();
157 checked_set (_master_encoding_threads, config->master_encoding_threads ());
158 checked_set (_server_encoding_threads, config->server_encoding_threads ());
159 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
160 checked_set (_analyse_ebur128, config->analyse_ebur128 ());
162 checked_set (_automatic_audio_analysis, config->automatic_audio_analysis ());
163 checked_set (_config_file, config->config_read_file());
164 checked_set (_cinemas_file, config->cinemas_file());
166 GeneralPage::config_changed ();
169 void export_cinemas_file ()
171 auto d = new wxFileDialog (
172 _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT("XML files (*.xml)|*.xml"),
173 wxFD_SAVE | wxFD_OVERWRITE_PROMPT
176 if (d->ShowModal () == wxID_OK) {
177 boost::filesystem::copy_file(Config::instance()->cinemas_file(), wx_to_std(d->GetPath()), boost::filesystem::copy_option::overwrite_if_exists);
182 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
183 void analyse_ebur128_changed ()
185 Config::instance()->set_analyse_ebur128 (_analyse_ebur128->GetValue());
189 void automatic_audio_analysis_changed ()
191 Config::instance()->set_automatic_audio_analysis (_automatic_audio_analysis->GetValue());
194 void master_encoding_threads_changed ()
196 Config::instance()->set_master_encoding_threads (_master_encoding_threads->GetValue());
199 void server_encoding_threads_changed ()
201 Config::instance()->set_server_encoding_threads (_server_encoding_threads->GetValue());
204 void config_file_changed ()
206 auto config = Config::instance();
207 boost::filesystem::path new_file = wx_to_std(_config_file->GetPath());
208 if (new_file == config->config_read_file()) {
211 bool copy_and_link = true;
212 if (boost::filesystem::exists(new_file)) {
213 auto d = new ConfigMoveDialog (_panel, new_file);
214 if (d->ShowModal() == wxID_OK) {
215 copy_and_link = false;
222 if (new_file != config->config_read_file()) {
223 config->copy_and_link (new_file);
226 config->link (new_file);
230 void cinemas_file_changed ()
232 Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
235 wxSpinCtrl* _master_encoding_threads;
236 wxSpinCtrl* _server_encoding_threads;
237 FilePickerCtrl* _config_file;
238 FilePickerCtrl* _cinemas_file;
239 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
240 CheckBox* _analyse_ebur128;
242 CheckBox* _automatic_audio_analysis;
246 class DefaultsPage : public Page
249 DefaultsPage (wxSize panel_size, int border)
250 : Page (panel_size, border)
253 wxString GetName () const override
255 return _("Defaults");
259 wxBitmap GetLargeIcon () const override
261 return wxBitmap(icon_path("defaults"), wxBITMAP_TYPE_PNG);
266 void setup () override
268 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
269 table->AddGrowableCol (1, 1);
270 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
273 add_label_to_sizer (table, _panel, _("Default duration of still images"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
274 auto s = new wxBoxSizer (wxHORIZONTAL);
275 _still_length = new wxSpinCtrl (_panel);
276 s->Add (_still_length);
277 add_label_to_sizer (s, _panel, _("s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
281 add_label_to_sizer (table, _panel, _("Default directory for new films"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
282 #ifdef DCPOMATIC_USE_OWN_PICKER
283 _directory = new DirPickerCtrl (_panel);
285 _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
287 table->Add (_directory, 1, wxEXPAND);
289 add_label_to_sizer (table, _panel, _("Default content type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
290 _dcp_content_type = new wxChoice (_panel, wxID_ANY);
291 table->Add (_dcp_content_type);
293 add_label_to_sizer (table, _panel, _("Default DCP audio channels"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
294 _dcp_audio_channels = new wxChoice (_panel, wxID_ANY);
295 table->Add (_dcp_audio_channels);
298 add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
299 auto s = new wxBoxSizer (wxHORIZONTAL);
300 _j2k_bandwidth = new wxSpinCtrl (_panel);
301 s->Add (_j2k_bandwidth);
302 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
307 add_label_to_sizer (table, _panel, _("Default audio delay"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
308 auto s = new wxBoxSizer (wxHORIZONTAL);
309 _audio_delay = new wxSpinCtrl (_panel);
310 s->Add (_audio_delay);
311 add_label_to_sizer (s, _panel, _("ms"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
315 add_label_to_sizer (table, _panel, _("Default standard"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
316 _standard = new wxChoice (_panel, wxID_ANY);
317 table->Add (_standard);
319 _enable_audio_language = new CheckBox(_panel, _("Default audio language"));
320 table->Add(_enable_audio_language, 1, wxEXPAND | wxALIGN_CENTRE_VERTICAL);
321 _audio_language = new LanguageTagWidget(_panel, _("Default audio language to use for new DCPs"), Config::instance()->default_audio_language(), wxString("cmnr-Hant-"));
322 table->Add(_audio_language->sizer());
324 table->Add (_enable_metadata["facility"] = new CheckBox (_panel, _("Default facility")), 0, wxALIGN_CENTRE_VERTICAL);
325 table->Add (_metadata["facility"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
327 table->Add (_enable_metadata["studio"] = new CheckBox (_panel, _("Default studio")), 0, wxALIGN_CENTRE_VERTICAL);
328 table->Add (_metadata["studio"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
330 table->Add (_enable_metadata["chain"] = new CheckBox (_panel, _("Default chain")), 0, wxALIGN_CENTRE_VERTICAL);
331 table->Add (_metadata["chain"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
333 table->Add (_enable_metadata["distributor"] = new CheckBox (_panel, _("Default distributor")), 0, wxALIGN_CENTRE_VERTICAL);
334 table->Add (_metadata["distributor"] = new wxTextCtrl (_panel, wxID_ANY, wxT("")), 0, wxEXPAND);
336 add_label_to_sizer (table, _panel, _("Default KDM directory"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
337 #ifdef DCPOMATIC_USE_OWN_PICKER
338 _kdm_directory = new DirPickerCtrl (_panel);
340 _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
342 table->Add (_kdm_directory, 1, wxEXPAND);
344 add_label_to_sizer (table, _panel, _("Default KDM type"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
345 _kdm_type = new KDMChoice (_panel);
346 table->Add (_kdm_type, 1, wxEXPAND);
348 add_label_to_sizer (table, _panel, _("Default KDM duration"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
349 _kdm_duration = new wxSpinCtrl (_panel);
350 _kdm_duration_unit = new wxChoice (_panel, wxID_ANY);
351 auto kdm_duration_sizer = new wxBoxSizer (wxHORIZONTAL);
352 kdm_duration_sizer->Add (_kdm_duration, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
353 kdm_duration_sizer->Add (_kdm_duration_unit, 0, wxEXPAND | wxRIGHT, DCPOMATIC_SIZER_GAP);
354 table->Add (kdm_duration_sizer, 1, wxEXPAND);
356 table->Add (_use_isdcf_name_by_default = new CheckBox(_panel, _("Use ISDCF name by default")), 0, wxALIGN_CENTRE_VERTICAL);
358 _still_length->SetRange (1, 3600);
359 _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
361 _directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
362 _kdm_directory->Bind (wxEVT_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::kdm_directory_changed, this));
363 _kdm_type->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_type_changed, this));
364 _kdm_duration_unit->Append (_("days"));
365 _kdm_duration_unit->Append (_("weeks"));
366 _kdm_duration_unit->Append (_("months"));
367 _kdm_duration_unit->Append (_("years"));
369 _kdm_duration->Bind (wxEVT_SPINCTRL, boost::bind(&DefaultsPage::kdm_duration_changed, this));
370 _kdm_duration_unit->Bind (wxEVT_CHOICE, boost::bind(&DefaultsPage::kdm_duration_changed, this));
372 _use_isdcf_name_by_default->bind(&DefaultsPage::use_isdcf_name_by_default_changed, this);
374 for (auto i: DCPContentType::all()) {
375 _dcp_content_type->Append (std_to_wx (i->pretty_name ()));
378 setup_audio_channels_choice (_dcp_audio_channels, 2);
380 _dcp_content_type->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
381 _dcp_audio_channels->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::dcp_audio_channels_changed, this));
383 _j2k_bandwidth->SetRange (50, 250);
384 _j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
386 _audio_delay->SetRange (-1000, 1000);
387 _audio_delay->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::audio_delay_changed, this));
389 _standard->Append (_("SMPTE"));
390 _standard->Append (_("Interop"));
391 _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
393 for (auto const& i: _enable_metadata) {
394 i.second->bind(&DefaultsPage::metadata_changed, this);
397 for (auto const& i: _metadata) {
398 i.second->Bind (wxEVT_TEXT, boost::bind(&DefaultsPage::metadata_changed, this));
401 _enable_audio_language->bind(&DefaultsPage::enable_audio_language_toggled, this);
402 _audio_language->Changed.connect(boost::bind(&DefaultsPage::audio_language_changed, this));
405 void config_changed () override
407 auto config = Config::instance ();
409 auto const ct = DCPContentType::all ();
410 for (size_t i = 0; i < ct.size(); ++i) {
411 if (ct[i] == config->default_dcp_content_type()) {
412 _dcp_content_type->SetSelection (i);
416 checked_set (_still_length, config->default_still_length ());
417 _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
418 _kdm_directory->SetPath (std_to_wx (config->default_kdm_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
419 _kdm_type->set (config->default_kdm_type());
420 checked_set (_use_isdcf_name_by_default, config->use_isdcf_name_by_default());
421 checked_set (_j2k_bandwidth, config->default_j2k_bandwidth() / 1000000);
422 _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
423 checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
424 checked_set (_audio_delay, config->default_audio_delay ());
425 checked_set (_standard, config->default_interop() ? 1 : 0);
426 auto dal = config->default_audio_language();
427 checked_set(_enable_audio_language, static_cast<bool>(dal));
428 checked_set(_audio_language, dal ? dal : boost::none);
430 auto metadata = config->default_metadata();
432 for (auto const& i: metadata) {
433 _enable_metadata[i.first]->SetValue(true);
434 checked_set (_metadata[i.first], i.second);
437 for (auto const& i: _enable_metadata) {
438 if (metadata.find(i.first) == metadata.end()) {
439 checked_set (i.second, false);
443 for (auto const& i: _metadata) {
444 if (metadata.find(i.first) == metadata.end()) {
445 checked_set (i.second, wxT(""));
449 checked_set (_kdm_duration, config->default_kdm_duration().duration);
450 switch (config->default_kdm_duration().unit) {
451 case RoughDuration::Unit::DAYS:
452 _kdm_duration->SetRange(1, 365);
453 checked_set (_kdm_duration_unit, 0);
455 case RoughDuration::Unit::WEEKS:
456 _kdm_duration->SetRange(1, 52);
457 checked_set (_kdm_duration_unit, 1);
459 case RoughDuration::Unit::MONTHS:
460 _kdm_duration->SetRange(1, 12);
461 checked_set (_kdm_duration_unit, 2);
463 case RoughDuration::Unit::YEARS:
464 _kdm_duration->SetRange(1, 40);
465 checked_set (_kdm_duration_unit, 3);
469 setup_sensitivity ();
472 void kdm_duration_changed ()
474 auto config = Config::instance();
475 auto duration = _kdm_duration->GetValue();
476 RoughDuration::Unit unit = RoughDuration::Unit::DAYS;
477 switch (_kdm_duration_unit->GetSelection()) {
479 unit = RoughDuration::Unit::DAYS;
482 unit = RoughDuration::Unit::WEEKS;
485 unit = RoughDuration::Unit::MONTHS;
488 unit = RoughDuration::Unit::YEARS;
491 config->set_default_kdm_duration (RoughDuration(duration, unit));
494 void j2k_bandwidth_changed ()
496 Config::instance()->set_default_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1000000);
499 void audio_delay_changed ()
501 Config::instance()->set_default_audio_delay (_audio_delay->GetValue());
504 void dcp_audio_channels_changed ()
506 int const s = _dcp_audio_channels->GetSelection ();
507 if (s != wxNOT_FOUND) {
508 Config::instance()->set_default_dcp_audio_channels (
509 locale_convert<int>(string_client_data(_dcp_audio_channels->GetClientObject(s)))
514 void directory_changed ()
516 Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
519 void kdm_directory_changed ()
521 Config::instance()->set_default_kdm_directory (wx_to_std (_kdm_directory->GetPath ()));
524 void kdm_type_changed ()
526 Config::instance()->set_default_kdm_type(_kdm_type->get());
529 void use_isdcf_name_by_default_changed ()
531 Config::instance()->set_use_isdcf_name_by_default (_use_isdcf_name_by_default->GetValue());
534 void still_length_changed ()
536 Config::instance()->set_default_still_length (_still_length->GetValue ());
539 void dcp_content_type_changed ()
541 auto ct = DCPContentType::all ();
542 Config::instance()->set_default_dcp_content_type (ct[_dcp_content_type->GetSelection()]);
545 void standard_changed ()
547 Config::instance()->set_default_interop (_standard->GetSelection() == 1);
550 void metadata_changed ()
552 map<string, string> metadata;
553 for (auto const& i: _enable_metadata) {
554 if (i.second->GetValue()) {
555 metadata[i.first] = wx_to_std(_metadata[i.first]->GetValue());
558 Config::instance()->set_default_metadata (metadata);
559 setup_sensitivity ();
562 void enable_audio_language_toggled()
565 audio_language_changed();
568 void audio_language_changed()
570 if (_enable_audio_language->get()) {
571 Config::instance()->set_default_audio_language(_audio_language->get().get_value_or(dcp::LanguageTag("en-US")));
573 Config::instance()->unset_default_audio_language();
577 void setup_sensitivity ()
579 _audio_language->enable(_enable_audio_language->get());
580 for (auto const& i: _enable_metadata) {
581 _metadata[i.first]->Enable(i.second->GetValue());
585 wxSpinCtrl* _j2k_bandwidth;
586 wxSpinCtrl* _audio_delay;
587 wxSpinCtrl* _still_length;
588 #ifdef DCPOMATIC_USE_OWN_PICKER
589 DirPickerCtrl* _directory;
590 DirPickerCtrl* _kdm_directory;
592 wxDirPickerCtrl* _directory;
593 wxDirPickerCtrl* _kdm_directory;
595 KDMChoice* _kdm_type;
596 wxSpinCtrl* _kdm_duration;
597 wxChoice* _kdm_duration_unit;
598 CheckBox* _use_isdcf_name_by_default;
599 wxChoice* _dcp_content_type;
600 wxChoice* _dcp_audio_channels;
602 CheckBox* _enable_audio_language;
603 LanguageTagWidget* _audio_language;
604 map<string, CheckBox*> _enable_metadata;
605 map<string, wxTextCtrl*> _metadata;
609 class EncodingServersPage : public Page
612 EncodingServersPage (wxSize panel_size, int border)
613 : Page (panel_size, border)
616 wxString GetName () const override
622 wxBitmap GetLargeIcon () const override
624 return wxBitmap(icon_path("servers"), wxBITMAP_TYPE_PNG);
629 void setup () override
631 _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
632 _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
634 vector<EditableListColumn> columns;
635 columns.push_back (EditableListColumn(_("IP address / host name")));
636 _servers_list = new EditableList<string, ServerDialog> (
639 boost::bind (&Config::servers, Config::instance()),
640 boost::bind (&Config::set_servers, Config::instance(), _1),
641 boost::bind (&EncodingServersPage::server_column, this, _1),
642 EditableListTitle::INVISIBLE,
643 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
646 _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
648 _use_any_servers->bind(&EncodingServersPage::use_any_servers_changed, this);
651 void config_changed () override
653 checked_set (_use_any_servers, Config::instance()->use_any_servers ());
654 _servers_list->refresh ();
657 void use_any_servers_changed ()
659 Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
662 string server_column (string s)
667 CheckBox* _use_any_servers;
668 EditableList<string, ServerDialog>* _servers_list;
672 class TMSPage : public Page
675 TMSPage (wxSize panel_size, int border)
676 : Page (panel_size, border)
679 wxString GetName () const override
685 wxBitmap GetLargeIcon () const override
687 return wxBitmap(icon_path("tms"), wxBITMAP_TYPE_PNG);
692 void setup () override
694 _upload = new CheckBox (_panel, _("Upload DCP to TMS after creation"));
695 _panel->GetSizer()->Add (_upload, 0, wxALL | wxEXPAND, _border);
697 wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
698 table->AddGrowableCol (1, 1);
699 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
701 add_label_to_sizer (table, _panel, _("Protocol"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
702 _tms_protocol = new wxChoice (_panel, wxID_ANY);
703 table->Add (_tms_protocol, 1, wxEXPAND);
705 _tms_passive = new CheckBox(_panel, _("Passive mode"));
706 table->Add(_tms_passive, 1, wxEXPAND);
709 add_label_to_sizer (table, _panel, _("IP address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
710 _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
711 table->Add (_tms_ip, 1, wxEXPAND);
713 add_label_to_sizer (table, _panel, _("Target path"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
714 _tms_path = new wxTextCtrl (_panel, wxID_ANY);
715 table->Add (_tms_path, 1, wxEXPAND);
717 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
718 _tms_user = new wxTextCtrl (_panel, wxID_ANY);
719 table->Add (_tms_user, 1, wxEXPAND);
721 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
722 _tms_password = new PasswordEntry (_panel);
723 table->Add (_tms_password->get_panel(), 1, wxEXPAND);
725 _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
726 _tms_protocol->Append (_("FTP (for Dolby)"));
728 _upload->bind(&TMSPage::upload_changed, this);
729 _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
730 _tms_passive->bind(&TMSPage::tms_passive_changed, this);
732 _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
733 _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
734 _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
735 _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
738 void config_changed () override
740 auto config = Config::instance ();
742 checked_set (_upload, config->upload_after_make_dcp());
743 checked_set (_tms_protocol, static_cast<int>(config->tms_protocol()));
744 checked_set(_tms_passive, config->tms_protocol() == FileTransferProtocol::FTP && config->tms_passive());
745 checked_set (_tms_ip, config->tms_ip ());
746 checked_set (_tms_path, config->tms_path ());
747 checked_set (_tms_user, config->tms_user ());
748 checked_set (_tms_password, config->tms_password ());
750 _tms_passive->Enable(config->tms_protocol() == FileTransferProtocol::FTP);
753 void upload_changed ()
755 Config::instance()->set_upload_after_make_dcp (_upload->GetValue());
758 void tms_protocol_changed ()
760 Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
763 void tms_passive_changed()
765 Config::instance()->set_tms_passive(_tms_passive->get());
768 void tms_ip_changed ()
770 Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
773 void tms_path_changed ()
775 Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
778 void tms_user_changed ()
780 Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
783 void tms_password_changed ()
785 Config::instance()->set_tms_password (_tms_password->get());
789 CheckBox* _tms_passive;
790 wxChoice* _tms_protocol;
792 wxTextCtrl* _tms_path;
793 wxTextCtrl* _tms_user;
794 PasswordEntry* _tms_password;
798 class EmailPage : public Page
801 EmailPage (wxSize panel_size, int border)
802 : Page (panel_size, border)
805 wxString GetName () const override
811 wxBitmap GetLargeIcon () const override
813 return wxBitmap(icon_path("email"), wxBITMAP_TYPE_PNG);
818 void setup () override
820 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
821 table->AddGrowableCol (1, 1);
822 _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
824 add_label_to_sizer (table, _panel, _("Outgoing mail server"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
826 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
827 _server = new wxTextCtrl (_panel, wxID_ANY);
828 s->Add (_server, 1, wxEXPAND | wxALL);
829 add_label_to_sizer (s, _panel, _("port"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
830 _port = new wxSpinCtrl (_panel, wxID_ANY);
831 _port->SetRange (0, 65535);
833 add_label_to_sizer (s, _panel, _("protocol"), false, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
834 _protocol = new wxChoice (_panel, wxID_ANY);
835 /* Make sure this matches the switches in config_changed and port_changed below */
836 _protocol->Append (_("Auto"));
837 _protocol->Append (_("Plain"));
838 _protocol->Append (_("STARTTLS"));
839 _protocol->Append (_("SSL"));
840 s->Add (_protocol, 1, wxALIGN_CENTER_VERTICAL);
841 table->Add (s, 1, wxEXPAND | wxALL);
844 add_label_to_sizer (table, _panel, _("User name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
845 _user = new wxTextCtrl (_panel, wxID_ANY);
846 table->Add (_user, 1, wxEXPAND | wxALL);
848 add_label_to_sizer (table, _panel, _("Password"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
849 _password = new PasswordEntry (_panel);
850 table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
852 table->AddSpacer (0);
853 _send_test_email = new Button (_panel, _("Send test email..."));
854 table->Add (_send_test_email);
856 _server->Bind (wxEVT_TEXT, boost::bind(&EmailPage::server_changed, this));
857 _port->Bind (wxEVT_SPINCTRL, boost::bind(&EmailPage::port_changed, this));
858 _protocol->Bind (wxEVT_CHOICE, boost::bind(&EmailPage::protocol_changed, this));
859 _user->Bind (wxEVT_TEXT, boost::bind(&EmailPage::user_changed, this));
860 _password->Changed.connect (boost::bind(&EmailPage::password_changed, this));
861 _send_test_email->Bind (wxEVT_BUTTON, boost::bind(&EmailPage::send_test_email_clicked, this));
864 void config_changed () override
866 auto config = Config::instance ();
868 checked_set (_server, config->mail_server());
869 checked_set (_port, config->mail_port());
870 switch (config->mail_protocol()) {
871 case EmailProtocol::AUTO:
872 checked_set (_protocol, 0);
874 case EmailProtocol::PLAIN:
875 checked_set (_protocol, 1);
877 case EmailProtocol::STARTTLS:
878 checked_set (_protocol, 2);
880 case EmailProtocol::SSL:
881 checked_set (_protocol, 3);
884 checked_set (_user, config->mail_user());
885 checked_set (_password, config->mail_password());
888 void server_changed ()
890 Config::instance()->set_mail_server(wx_to_std(_server->GetValue()));
895 Config::instance()->set_mail_port(_port->GetValue());
898 void protocol_changed ()
900 switch (_protocol->GetSelection()) {
902 Config::instance()->set_mail_protocol(EmailProtocol::AUTO);
905 Config::instance()->set_mail_protocol(EmailProtocol::PLAIN);
908 Config::instance()->set_mail_protocol(EmailProtocol::STARTTLS);
911 Config::instance()->set_mail_protocol(EmailProtocol::SSL);
918 Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
921 void password_changed ()
923 Config::instance()->set_mail_password(_password->get());
926 void send_test_email_clicked ()
928 auto dialog = new SendTestEmailDialog(_panel);
929 auto result = dialog->ShowModal();
931 if (result == wxID_OK) {
933 wx_to_std(dialog->from()),
934 { wx_to_std(dialog->to()) },
935 wx_to_std(_("DCP-o-matic test email")),
936 wx_to_std(_("This is a test email from DCP-o-matic."))
938 auto config = Config::instance();
940 emailer.send (config->mail_server(), config->mail_port(), config->mail_protocol(), config->mail_user(), config->mail_password());
941 } catch (NetworkError& e) {
942 error_dialog (_panel, std_to_wx(e.summary()), std_to_wx(e.detail().get_value_or("")));
944 } catch (std::exception& e) {
945 error_dialog (_panel, _("Test email sending failed."), std_to_wx(e.what()));
948 error_dialog (_panel, _("Test email sending failed."));
951 message_dialog (_panel, _("Test email sent."));
959 PasswordEntry* _password;
960 Button* _send_test_email;
964 class KDMEmailPage : public Page
968 KDMEmailPage (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 override
979 return _("KDM Email");
983 wxBitmap GetLargeIcon () const override
985 return wxBitmap(icon_path("kdm_email"), wxBITMAP_TYPE_PNG);
990 void setup () override
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 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
997 _subject = new wxTextCtrl (_panel, wxID_ANY);
998 table->Add (_subject, 1, wxEXPAND | wxALL);
1000 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1001 _from = new wxTextCtrl (_panel, wxID_ANY);
1002 table->Add (_from, 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::kdm_cc, Config::instance()),
1011 bind (&Config::set_kdm_cc, Config::instance(), _1),
1012 [] (string s, int) {
1015 EditableListTitle::VISIBLE,
1016 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1018 table->Add (_cc, 1, wxEXPAND | wxALL);
1020 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1021 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1022 table->Add (_bcc, 1, wxEXPAND | wxALL);
1024 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1025 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1027 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1028 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1032 _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
1033 _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
1034 _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
1035 _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
1036 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
1039 void config_changed () override
1041 auto config = Config::instance ();
1043 checked_set (_subject, config->kdm_subject ());
1044 checked_set (_from, config->kdm_from ());
1045 checked_set (_bcc, config->kdm_bcc ());
1046 checked_set (_email, Config::instance()->kdm_email ());
1049 void kdm_subject_changed ()
1051 Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
1054 void kdm_from_changed ()
1056 Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
1059 void kdm_bcc_changed ()
1061 Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
1064 void kdm_email_changed ()
1066 if (_email->GetValue().IsEmpty ()) {
1067 /* Sometimes we get sent an erroneous notification that the email
1068 is empty; I don't know why.
1072 Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
1077 Config::instance()->reset_kdm_email ();
1078 checked_set (_email, Config::instance()->kdm_email ());
1081 wxTextCtrl* _subject;
1083 EditableList<string, EmailDialog>* _cc;
1086 wxButton* _reset_email;
1090 class NotificationsPage : public Page
1093 NotificationsPage (wxSize panel_size, int border)
1094 #ifdef DCPOMATIC_OSX
1095 /* We have to force both width and height of this one */
1096 : Page (wxSize (panel_size.GetWidth(), 128), border)
1098 : Page (panel_size, border)
1102 wxString GetName () const override
1104 return _("Notifications");
1107 #ifdef DCPOMATIC_OSX
1108 wxBitmap GetLargeIcon () const override
1110 return wxBitmap(icon_path("notifications"), wxBITMAP_TYPE_PNG);
1115 void setup () override
1117 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1118 table->AddGrowableCol (1, 1);
1119 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1121 _enable_message_box = new CheckBox (_panel, _("Message box"));
1122 table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
1123 table->AddSpacer (0);
1125 _enable_email = new CheckBox (_panel, _("Email"));
1126 table->Add (_enable_email, 1, wxEXPAND | wxALL);
1127 table->AddSpacer (0);
1129 add_label_to_sizer (table, _panel, _("Subject"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1130 _subject = new wxTextCtrl (_panel, wxID_ANY);
1131 table->Add (_subject, 1, wxEXPAND | wxALL);
1133 add_label_to_sizer (table, _panel, _("From address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1134 _from = new wxTextCtrl (_panel, wxID_ANY);
1135 table->Add (_from, 1, wxEXPAND | wxALL);
1137 add_label_to_sizer (table, _panel, _("To address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1138 _to = new wxTextCtrl (_panel, wxID_ANY);
1139 table->Add (_to, 1, wxEXPAND | wxALL);
1141 vector<EditableListColumn> columns;
1142 columns.push_back (EditableListColumn(_("Address")));
1143 add_label_to_sizer (table, _panel, _("CC addresses"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1144 _cc = new EditableList<string, EmailDialog> (
1147 bind (&Config::notification_cc, Config::instance()),
1148 bind (&Config::set_notification_cc, Config::instance(), _1),
1149 [] (string s, int) {
1152 EditableListTitle::VISIBLE,
1153 EditableListButton::NEW | EditableListButton::EDIT | EditableListButton::REMOVE
1155 table->Add (_cc, 1, wxEXPAND | wxALL);
1157 add_label_to_sizer (table, _panel, _("BCC address"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1158 _bcc = new wxTextCtrl (_panel, wxID_ANY);
1159 table->Add (_bcc, 1, wxEXPAND | wxALL);
1161 _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1162 _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
1164 _reset_email = new Button (_panel, _("Reset to default subject and text"));
1165 _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
1169 _enable_message_box->bind(&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX);
1170 _enable_email->bind(&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL);
1172 _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
1173 _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
1174 _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
1175 _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
1176 _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
1177 _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
1179 setup_sensitivity ();
1182 void setup_sensitivity ()
1184 bool const s = _enable_email->GetValue();
1185 _subject->Enable(s);
1191 _reset_email->Enable(s);
1194 void config_changed () override
1196 auto config = Config::instance ();
1198 checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
1199 checked_set (_enable_email, config->notification(Config::EMAIL));
1200 checked_set (_subject, config->notification_subject ());
1201 checked_set (_from, config->notification_from ());
1202 checked_set (_to, config->notification_to ());
1203 checked_set (_bcc, config->notification_bcc ());
1204 checked_set (_email, Config::instance()->notification_email ());
1206 setup_sensitivity ();
1209 void notification_subject_changed ()
1211 Config::instance()->set_notification_subject(wx_to_std(_subject->GetValue()));
1214 void notification_from_changed ()
1216 Config::instance()->set_notification_from(wx_to_std(_from->GetValue()));
1219 void notification_to_changed ()
1221 Config::instance()->set_notification_to(wx_to_std(_to->GetValue()));
1224 void notification_bcc_changed ()
1226 Config::instance()->set_notification_bcc(wx_to_std(_bcc->GetValue()));
1229 void notification_email_changed ()
1231 if (_email->GetValue().IsEmpty()) {
1232 /* Sometimes we get sent an erroneous notification that the email
1233 is empty; I don't know why.
1237 Config::instance()->set_notification_email(wx_to_std(_email->GetValue()));
1242 Config::instance()->reset_notification_email();
1243 checked_set (_email, Config::instance()->notification_email());
1246 void type_changed (CheckBox* b, Config::Notification n)
1248 Config::instance()->set_notification(n, b->GetValue());
1249 setup_sensitivity ();
1252 CheckBox* _enable_message_box;
1253 CheckBox* _enable_email;
1255 wxTextCtrl* _subject;
1258 EditableList<string, EmailDialog>* _cc;
1261 wxButton* _reset_email;
1265 class CoverSheetPage : public Page
1269 CoverSheetPage (wxSize panel_size, int border)
1270 #ifdef DCPOMATIC_OSX
1271 /* We have to force both width and height of this one */
1272 : Page (wxSize (panel_size.GetWidth(), 128), border)
1274 : Page (panel_size, border)
1278 wxString GetName () const override
1280 return _("Cover Sheet");
1283 #ifdef DCPOMATIC_OSX
1284 wxBitmap GetLargeIcon () const override
1286 return wxBitmap(icon_path("cover_sheet"), wxBITMAP_TYPE_PNG);
1291 void setup () override
1293 _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
1294 _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
1296 _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
1297 _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
1299 _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
1300 _reset_cover_sheet->Bind (wxEVT_BUTTON, boost::bind (&CoverSheetPage::reset_cover_sheet, this));
1303 void config_changed () override
1305 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1308 void cover_sheet_changed ()
1310 if (_cover_sheet->GetValue().IsEmpty ()) {
1311 /* Sometimes we get sent an erroneous notification that the cover sheet
1312 is empty; I don't know why.
1316 Config::instance()->set_cover_sheet(wx_to_std(_cover_sheet->GetValue()));
1319 void reset_cover_sheet ()
1321 Config::instance()->reset_cover_sheet();
1322 checked_set (_cover_sheet, Config::instance()->cover_sheet());
1325 wxTextCtrl* _cover_sheet;
1326 wxButton* _reset_cover_sheet;
1330 class IdentifiersPage : public Page
1333 IdentifiersPage (wxSize panel_size, int border)
1334 : Page (panel_size, border)
1337 wxString GetName () const override
1339 return _("Identifiers");
1342 #ifdef DCPOMATIC_OSX
1343 wxBitmap GetLargeIcon () const override
1345 return wxBitmap(icon_path("identifiers"), wxBITMAP_TYPE_PNG);
1350 void setup () override
1352 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1353 table->AddGrowableCol (1, 1);
1355 add_label_to_sizer (table, _panel, _("Issuer"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1356 _issuer = new wxTextCtrl (_panel, wxID_ANY);
1357 _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."));
1358 table->Add (_issuer, 1, wxALL | wxEXPAND);
1360 add_label_to_sizer (table, _panel, _("Creator"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1361 _creator = new wxTextCtrl (_panel, wxID_ANY);
1362 _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."));
1363 table->Add (_creator, 1, wxALL | wxEXPAND);
1365 add_label_to_sizer (table, _panel, _("Company name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1366 _company_name = new wxTextCtrl (_panel, wxID_ANY);
1367 _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."));
1368 table->Add (_company_name, 1, wxALL | wxEXPAND);
1370 add_label_to_sizer (table, _panel, _("Product name"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1371 _product_name = new wxTextCtrl (_panel, wxID_ANY);
1372 _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."));
1373 table->Add (_product_name, 1, wxALL | wxEXPAND);
1375 add_label_to_sizer (table, _panel, _("Product version"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1376 _product_version = new wxTextCtrl (_panel, wxID_ANY);
1377 _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."));
1378 table->Add (_product_version, 1, wxALL | wxEXPAND);
1380 add_label_to_sizer (table, _panel, _("JPEG2000 comment"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1381 _j2k_comment = new wxTextCtrl (_panel, wxID_ANY);
1382 _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."));
1383 table->Add (_j2k_comment, 1, wxALL | wxEXPAND);
1385 _panel->GetSizer()->Add (table, 0, wxEXPAND | wxALL, _border);
1387 _issuer->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::issuer_changed, this));
1388 _creator->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::creator_changed, this));
1389 _company_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::company_name_changed, this));
1390 _product_name->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_name_changed, this));
1391 _product_version->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::product_version_changed, this));
1392 _j2k_comment->Bind (wxEVT_TEXT, boost::bind(&IdentifiersPage::j2k_comment_changed, this));
1395 void config_changed () override
1397 auto config = Config::instance ();
1398 checked_set (_issuer, config->dcp_issuer ());
1399 checked_set (_creator, config->dcp_creator ());
1400 checked_set (_company_name, config->dcp_company_name ());
1401 checked_set (_product_name, config->dcp_product_name ());
1402 checked_set (_product_version, config->dcp_product_version ());
1403 checked_set (_j2k_comment, config->dcp_j2k_comment ());
1406 void issuer_changed ()
1408 Config::instance()->set_dcp_issuer(wx_to_std(_issuer->GetValue()));
1411 void creator_changed ()
1413 Config::instance()->set_dcp_creator(wx_to_std(_creator->GetValue()));
1416 void company_name_changed ()
1418 Config::instance()->set_dcp_company_name(wx_to_std(_company_name->GetValue()));
1421 void product_name_changed ()
1423 Config::instance()->set_dcp_product_name(wx_to_std(_product_name->GetValue()));
1426 void product_version_changed ()
1428 Config::instance()->set_dcp_product_version(wx_to_std(_product_version->GetValue()));
1431 void j2k_comment_changed ()
1433 Config::instance()->set_dcp_j2k_comment (wx_to_std(_j2k_comment->GetValue()));
1436 wxTextCtrl* _issuer;
1437 wxTextCtrl* _creator;
1438 wxTextCtrl* _company_name;
1439 wxTextCtrl* _product_name;
1440 wxTextCtrl* _product_version;
1441 wxTextCtrl* _j2k_comment;
1445 /** @class AdvancedPage
1446 * @brief Advanced page of the preferences dialog.
1448 class AdvancedPage : public Page
1451 AdvancedPage (wxSize panel_size, int border)
1452 : Page (panel_size, border)
1455 wxString GetName () const override
1457 return _("Advanced");
1460 #ifdef DCPOMATIC_OSX
1461 wxBitmap GetLargeIcon () const override
1463 return wxBitmap(icon_path("advanced"), wxBITMAP_TYPE_PNG);
1468 void add_top_aligned_label_to_sizer (wxSizer* table, wxWindow* parent, wxString text)
1470 int flags = wxALIGN_TOP | wxTOP | wxLEFT;
1472 flags |= wxALIGN_RIGHT;
1475 wxStaticText* m = new StaticText (parent, text);
1476 table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
1479 void setup () override
1481 auto table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
1482 table->AddGrowableCol (1, 1);
1483 _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
1486 add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1487 wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
1488 _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
1489 s->Add (_maximum_j2k_bandwidth, 1);
1490 add_label_to_sizer (s, _panel, _("Mbit/s"), false, 0, wxLEFT | wxALIGN_CENTRE_VERTICAL);
1494 add_label_to_sizer (table, _panel, _("Video display mode"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1495 _video_display_mode = new wxChoice (_panel, wxID_ANY);
1496 table->Add (_video_display_mode);
1498 auto restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
1499 auto font = restart->GetFont();
1500 font.SetStyle (wxFONTSTYLE_ITALIC);
1501 font.SetPointSize (font.GetPointSize() - 1);
1502 restart->SetFont (font);
1503 table->AddSpacer (0);
1505 _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
1506 table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1507 table->AddSpacer (0);
1509 _allow_any_container = new CheckBox (_panel, _("Allow full-frame and non-standard container ratios"));
1510 table->Add (_allow_any_container, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1511 restart = new StaticText (_panel, _("(restart DCP-o-matic to see all ratios)"));
1512 table->Add (restart, 1, wxEXPAND | wxALL | wxALIGN_CENTRE_VERTICAL);
1513 restart->SetFont (font);
1515 _allow_96khz_audio = new CheckBox (_panel, _("Allow creation of DCPs with 96kHz audio"));
1516 table->Add (_allow_96khz_audio, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1517 table->AddSpacer (0);
1519 _use_all_audio_channels = new CheckBox(_panel, _("Allow mapping to all audio channels"));
1520 table->Add(_use_all_audio_channels, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1521 table->AddSpacer(0);
1523 _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors"));
1524 table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1525 table->AddSpacer (0);
1527 _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
1528 table->Add (_only_servers_encode, 1, wxEXPAND | wxLEFT, DCPOMATIC_SIZER_GAP);
1529 table->AddSpacer (0);
1532 add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true, 0, wxLEFT | wxRIGHT | wxALIGN_CENTRE_VERTICAL);
1533 auto s = new wxBoxSizer (wxHORIZONTAL);
1534 _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
1535 s->Add (_frames_in_memory_multiplier, 1);
1540 auto format = create_label (_panel, _("DCP metadata filename format"), true);
1541 #ifdef DCPOMATIC_OSX
1542 auto align = new wxBoxSizer (wxHORIZONTAL);
1543 align->Add (format, 0, wxTOP, 2);
1544 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1546 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1548 dcp::NameFormat::Map titles;
1549 titles['t'] = wx_to_std (_("type (cpl/pkl)"));
1550 dcp::NameFormat::Map examples;
1551 examples['t'] = "cpl";
1552 _dcp_metadata_filename_format = new NameFormatEditor (
1553 _panel, Config::instance()->dcp_metadata_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.xml"
1555 table->Add (_dcp_metadata_filename_format->panel(), 1, wxEXPAND | wxALL);
1559 auto format = create_label (_panel, _("DCP asset filename format"), true);
1560 #ifdef DCPOMATIC_OSX
1561 auto align = new wxBoxSizer (wxHORIZONTAL);
1562 align->Add (format, 0, wxTOP, 2);
1563 table->Add (align, 0, wxALIGN_RIGHT | wxRIGHT, DCPOMATIC_SIZER_GAP - 2);
1565 table->Add (format, 0, wxTOP | wxLEFT | wxRIGHT | wxALIGN_TOP, DCPOMATIC_SIZER_GAP);
1567 dcp::NameFormat::Map titles;
1568 titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
1569 titles['r'] = wx_to_std (_("reel number"));
1570 titles['n'] = wx_to_std (_("number of reels"));
1571 titles['c'] = wx_to_std (_("content filename"));
1572 dcp::NameFormat::Map examples;
1573 examples['t'] = "j2c";
1574 examples['r'] = "1";
1575 examples['n'] = "4";
1576 examples['c'] = "myfile.mp4";
1577 _dcp_asset_filename_format = new NameFormatEditor (
1578 _panel, Config::instance()->dcp_asset_filename_format(), titles, examples, "_eb1c112c-ca3c-4ae6-9263-c6714ff05d64.mxf"
1580 table->Add (_dcp_asset_filename_format->panel(), 1, wxEXPAND | wxALL);
1584 add_top_aligned_label_to_sizer (table, _panel, _("Log"));
1585 auto t = new wxFlexGridSizer (2);
1586 _log_general = new CheckBox (_panel, _("General"));
1587 t->Add (_log_general, 1, wxEXPAND | wxALL);
1588 _log_warning = new CheckBox (_panel, _("Warnings"));
1589 t->Add (_log_warning, 1, wxEXPAND | wxALL);
1590 _log_error = new CheckBox (_panel, _("Errors"));
1591 t->Add (_log_error, 1, wxEXPAND | wxALL);
1592 /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
1593 _log_timing = new CheckBox (_panel, S_("Config|Timing"));
1594 t->Add (_log_timing, 1, wxEXPAND | wxALL);
1595 _log_debug_threed = new CheckBox (_panel, _("Debug: 3D"));
1596 t->Add (_log_debug_threed, 1, wxEXPAND | wxALL);
1597 _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
1598 t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
1599 _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
1600 t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
1601 _log_debug_video_view = new CheckBox (_panel, _("Debug: video view"));
1602 t->Add (_log_debug_video_view, 1, wxEXPAND | wxALL);
1603 _log_debug_player = new CheckBox (_panel, _("Debug: player"));
1604 t->Add (_log_debug_player, 1, wxEXPAND | wxALL);
1605 _log_debug_audio_analysis = new CheckBox (_panel, _("Debug: audio analysis"));
1606 t->Add (_log_debug_audio_analysis, 1, wxEXPAND | wxALL);
1607 table->Add (t, 0, wxALL, 6);
1610 #ifdef DCPOMATIC_WINDOWS
1611 _win32_console = new CheckBox (_panel, _("Open console window"));
1612 table->Add (_win32_console, 1, wxEXPAND | wxALL);
1613 table->AddSpacer (0);
1616 _maximum_j2k_bandwidth->SetRange (1, 1000);
1617 _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
1618 _video_display_mode->Append (_("Simple (safer)"));
1619 #if wxCHECK_VERSION(3, 1, 0)
1620 _video_display_mode->Append (_("OpenGL (faster)"));
1622 _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
1623 _allow_any_dcp_frame_rate->bind(&AdvancedPage::allow_any_dcp_frame_rate_changed, this);
1624 _allow_any_container->bind(&AdvancedPage::allow_any_container_changed, this);
1625 _allow_96khz_audio->bind(&AdvancedPage::allow_96khz_audio_changed, this);
1626 _use_all_audio_channels->bind(&AdvancedPage::use_all_channels_changed, this);
1627 _show_experimental_audio_processors->bind(&AdvancedPage::show_experimental_audio_processors_changed, this);
1628 _only_servers_encode->bind(&AdvancedPage::only_servers_encode_changed, this);
1629 _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
1630 _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
1631 _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
1632 _log_general->bind(&AdvancedPage::log_changed, this);
1633 _log_warning->bind(&AdvancedPage::log_changed, this);
1634 _log_error->bind(&AdvancedPage::log_changed, this);
1635 _log_timing->bind(&AdvancedPage::log_changed, this);
1636 _log_debug_threed->bind(&AdvancedPage::log_changed, this);
1637 _log_debug_encode->bind(&AdvancedPage::log_changed, this);
1638 _log_debug_email->bind(&AdvancedPage::log_changed, this);
1639 _log_debug_video_view->bind(&AdvancedPage::log_changed, this);
1640 _log_debug_player->bind(&AdvancedPage::log_changed, this);
1641 _log_debug_audio_analysis->bind(&AdvancedPage::log_changed, this);
1642 #ifdef DCPOMATIC_WINDOWS
1643 _win32_console->bind(&AdvancedPage::win32_console_changed, this);
1647 void config_changed () override
1649 auto config = Config::instance ();
1651 checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
1652 switch (config->video_view_type()) {
1653 case Config::VIDEO_VIEW_SIMPLE:
1654 checked_set (_video_display_mode, 0);
1656 case Config::VIDEO_VIEW_OPENGL:
1657 checked_set (_video_display_mode, 1);
1660 checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
1661 checked_set (_allow_any_container, config->allow_any_container ());
1662 checked_set (_allow_96khz_audio, config->allow_96khz_audio());
1663 checked_set (_use_all_audio_channels, config->use_all_audio_channels());
1664 checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ());
1665 checked_set (_only_servers_encode, config->only_servers_encode ());
1666 checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
1667 checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
1668 checked_set (_log_error, config->log_types() & LogEntry::TYPE_ERROR);
1669 checked_set (_log_timing, config->log_types() & LogEntry::TYPE_TIMING);
1670 checked_set (_log_debug_threed, config->log_types() & LogEntry::TYPE_DEBUG_THREE_D);
1671 checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
1672 checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
1673 checked_set (_log_debug_video_view, config->log_types() & LogEntry::TYPE_DEBUG_VIDEO_VIEW);
1674 checked_set (_log_debug_player, config->log_types() & LogEntry::TYPE_DEBUG_PLAYER);
1675 checked_set (_log_debug_audio_analysis, config->log_types() & LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS);
1676 checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
1677 #ifdef DCPOMATIC_WINDOWS
1678 checked_set (_win32_console, config->win32_console());
1682 void maximum_j2k_bandwidth_changed ()
1684 Config::instance()->set_maximum_j2k_bandwidth(_maximum_j2k_bandwidth->GetValue() * 1000000);
1687 void video_display_mode_changed ()
1689 if (_video_display_mode->GetSelection() == 0) {
1690 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_SIMPLE);
1692 Config::instance()->set_video_view_type(Config::VIDEO_VIEW_OPENGL);
1696 void frames_in_memory_multiplier_changed ()
1698 Config::instance()->set_frames_in_memory_multiplier(_frames_in_memory_multiplier->GetValue());
1701 void allow_any_dcp_frame_rate_changed ()
1703 Config::instance()->set_allow_any_dcp_frame_rate(_allow_any_dcp_frame_rate->GetValue());
1706 void allow_any_container_changed ()
1708 Config::instance()->set_allow_any_container(_allow_any_container->GetValue());
1711 void allow_96khz_audio_changed ()
1713 Config::instance()->set_allow_96hhz_audio(_allow_96khz_audio->GetValue());
1716 void use_all_channels_changed ()
1718 Config::instance()->set_use_all_audio_channels(_use_all_audio_channels->GetValue());
1721 void show_experimental_audio_processors_changed ()
1723 Config::instance()->set_show_experimental_audio_processors(_show_experimental_audio_processors->GetValue());
1726 void only_servers_encode_changed ()
1728 Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue());
1731 void dcp_metadata_filename_format_changed ()
1733 Config::instance()->set_dcp_metadata_filename_format(_dcp_metadata_filename_format->get());
1736 void dcp_asset_filename_format_changed ()
1738 Config::instance()->set_dcp_asset_filename_format(_dcp_asset_filename_format->get());
1744 if (_log_general->GetValue ()) {
1745 types |= LogEntry::TYPE_GENERAL;
1747 if (_log_warning->GetValue ()) {
1748 types |= LogEntry::TYPE_WARNING;
1750 if (_log_error->GetValue ()) {
1751 types |= LogEntry::TYPE_ERROR;
1753 if (_log_timing->GetValue ()) {
1754 types |= LogEntry::TYPE_TIMING;
1756 if (_log_debug_threed->GetValue ()) {
1757 types |= LogEntry::TYPE_DEBUG_THREE_D;
1759 if (_log_debug_encode->GetValue ()) {
1760 types |= LogEntry::TYPE_DEBUG_ENCODE;
1762 if (_log_debug_email->GetValue ()) {
1763 types |= LogEntry::TYPE_DEBUG_EMAIL;
1765 if (_log_debug_video_view->GetValue()) {
1766 types |= LogEntry::TYPE_DEBUG_VIDEO_VIEW;
1768 if (_log_debug_player->GetValue()) {
1769 types |= LogEntry::TYPE_DEBUG_PLAYER;
1771 if (_log_debug_audio_analysis->GetValue()) {
1772 types |= LogEntry::TYPE_DEBUG_AUDIO_ANALYSIS;
1774 Config::instance()->set_log_types (types);
1777 #ifdef DCPOMATIC_WINDOWS
1778 void win32_console_changed ()
1780 Config::instance()->set_win32_console(_win32_console->GetValue());
1784 wxSpinCtrl* _maximum_j2k_bandwidth = nullptr;
1785 wxChoice* _video_display_mode = nullptr;
1786 wxSpinCtrl* _frames_in_memory_multiplier = nullptr;
1787 CheckBox* _allow_any_dcp_frame_rate = nullptr;
1788 CheckBox* _allow_any_container = nullptr;
1789 CheckBox* _allow_96khz_audio = nullptr;
1790 CheckBox* _use_all_audio_channels = nullptr;
1791 CheckBox* _show_experimental_audio_processors = nullptr;
1792 CheckBox* _only_servers_encode = nullptr;
1793 NameFormatEditor* _dcp_metadata_filename_format = nullptr;
1794 NameFormatEditor* _dcp_asset_filename_format = nullptr;
1795 CheckBox* _log_general = nullptr;
1796 CheckBox* _log_warning = nullptr;
1797 CheckBox* _log_error = nullptr;
1798 CheckBox* _log_timing = nullptr;
1799 CheckBox* _log_debug_threed = nullptr;
1800 CheckBox* _log_debug_encode = nullptr;
1801 CheckBox* _log_debug_email = nullptr;
1802 CheckBox* _log_debug_video_view = nullptr;
1803 CheckBox* _log_debug_player = nullptr;
1804 CheckBox* _log_debug_audio_analysis = nullptr;
1805 #ifdef DCPOMATIC_WINDOWS
1806 CheckBox* _win32_console = nullptr;
1811 wxPreferencesEditor*
1812 create_full_config_dialog ()
1814 auto e = new wxPreferencesEditor ();
1816 #ifdef DCPOMATIC_OSX
1817 /* Width that we force some of the config panels to be on OSX so that
1818 the containing window doesn't shrink too much when we select those panels.
1819 This is obviously an unpleasant hack.
1821 wxSize ps = wxSize (750, -1);
1822 int const border = 16;
1824 wxSize ps = wxSize (-1, -1);
1825 int const border = 8;
1828 e->AddPage (new FullGeneralPage (ps, border));
1829 e->AddPage (new SoundPage (ps, border));
1830 e->AddPage (new DefaultsPage (ps, border));
1831 e->AddPage (new EncodingServersPage(ps, border));
1832 e->AddPage (new KeysPage (ps, border));
1833 e->AddPage (new TMSPage (ps, border));
1834 e->AddPage (new EmailPage (ps, border));
1835 e->AddPage (new KDMEmailPage (ps, border));
1836 e->AddPage (new NotificationsPage (ps, border));
1837 e->AddPage (new CoverSheetPage (ps, border));
1838 e->AddPage (new IdentifiersPage (ps, border));
1839 e->AddPage (new AdvancedPage (ps, border));